本章是上一章的繼續,再獲取到物件型別後,接下來做的事情。
第一部分 動態呼叫成員——呼叫方法,檢索或更改屬性,以及字段
方法1:利用info類呼叫類成員
1.用methodinfo類呼叫方法:
object invoke(object obj, object parameters)
其中,第1個引數obj,是物件的例項(靜態方法相應引數為null);第2個引數parameters是要傳遞到方法中的引數陣列;返回值為object型別,因此,要對結果進行強制型別轉換。示例如下:
public
class
mathclass
[stathread]
static
void
main()
;methodinfo method
=objmath.gettype().getmethod(
"multiply");
intresult =(
int)method.invoke(objmath, paramarray);}}
其中,objmath.gettype()
.getmethod(
"multiply
")方法,預設搜尋所有共有成員,可以使用其過載方法:
objmath.gettype()
.getmethod(
"multiply
", bindingflag.nonpublic),從而獲取非公有成員。
2.用propertyinfo類呼叫屬性:
getvalue(object obj, object index)
setvalue(object obj, object newvalue, object index)
其中,index為索引器(靜態設為null),obj為物件的例項(靜態設為null),返回值同樣為object型別。示例如下:
public
class
human
set}
[stathread]
static
void
main()
}3.用fieldinfo類呼叫字段:
getvalue(object obj)
setvalue(object obj, object value)
fieldinfo類使用同propertyinfo,只是沒有index罷了。示例略。
方法2:利用invokemember()方法呼叫類成員
3個過載,最常用的如下:
object invokemember(
string
name,
//要呼叫的物件名:可以是屬性名/方法名/欄位名
bindingflags invokeattr,
//搜尋成員的條件,以及如何處理第乙個引數:
//如bindingflags.invokemethod表示第乙個引數為方法名;
或setproperty
表示第乙個引數為屬性名;
或getfield
表示第乙個引數為欄位名;
binder binder,
//一般設為null,則會使用預設的defaultbinder,對提供的引數進行型別轉換,從原型別轉為目標型別
object target,
//呼叫成員的型別的例項(靜態成員為null)
object args
//對方法而言,是方法引數陣列;對欄位/屬性而言,獲取時是null,設定時是newvalue
);
1.呼叫方法:
methodinfo類的invoke()方法,不能直接處理過載方法,即無法判斷使用哪個過載方法,而invokemember則可以自動找到匹配的過載方法。示例如下:
type mathtype
=typeof
(system.math);
object
paramarray =;
intresult =(
int)mathtype.invokemember(
"max",
bindingflags.public
|bindingflags.invokemethod
|bindingflags.static,
null
, null
, paramarray);
當然,如果使用methodinfo類的invoke()方法處理過載方法,要輔助以selectmethod()先找到對應的過載方法,然後才能呼叫。
2.操縱屬性
得到屬性用bindingflags.getproperty,同時引數陣列為null;設定屬性用bindingflags.setproperty,示例如下:
type humantype
=typeof
(human);
human newhuman
=new
human();
//設定私有屬性name
object
paramarray =;
humantype.invokemember(
"name",
bindingflags.nonpublic
|bindingflags.instance
|bindingflags.setproperty,
null
, newhuman, paramarray);
//得到私有屬性name型別物件
string
result
=humantype.invokemember(
"get_name",
bindingflags.nonpublic
|bindingflags.instance
|bindingflags.invokemethod,
null
, newhuman,
null
);補注:
在msil中屬性其實就是方法,所以對屬性的操縱也可以使用如下方式(以get為例):
humantype.invokemember(
"get_name",
bindingflags.nonpublic
|bindingflags.instance
|bindingflags.invokemethod,
null
, newhuman,
null
); 同理,可以使用methodinfo.invokemethod()改寫為:
human objhuman
=new
human();
object paramarray =;
methodinfo method
=objhuman.gettype().getmethod(
"get_name");
string
result =(
string
)method.invoke(objhuman, paramarray);
3.操縱字段
基本上同於"操縱屬性",不再多言。
兩種方法的比較:
type的invokemember()方法靈活且功能強大,應該優先使用;僅當需要處理元資料時,才使用info類。
第二部分 用反射模擬委託功能
之所以要模擬,是因為委託時型別安全的(編譯期)——區別於反射(執行期),所以小型程式要盡量使用委託。
委託不區分靜態方法/例項方法——區別於反射。
模擬**如下:
public
class
invoker
public
invoker(object targetobject, string targetmethod)
public
object invoke(object args)
else
return
mytype.invokemember(mymethod, mybindingflags,
null
, myobject, args);
}else}}
public
class
mymath
public
intmultiply(
intx,
inty)
static
void
main()
;mymath objmath
=new
mymath();
invoker mydelegate
=new
invoker(objmath,
"multiply");
result
=mydelegate.invoke(args);
console.writeline(
"the product of and is:
", args[
0], args[
1], result);
invoker objdelegate
=new
invoker(
typeof
(mymath),
"pow");
result
=objdelegate.invoke(args);
console.writeline(
"the product of and is:
", args[
0], args[
1], result);
}catch}}
在模擬中,委託可以使用委託鏈實現"反射"過載方法。
pythond物件 異常 反射的學習筆記
python多繼承,剛開始我是表示驚訝的,畢竟學的php,哪來的多繼承?頂多也就是利用介面模擬多繼承後者使用反射機制實現。那麼還是來看看python的強大吧 1 首先,python的類繼承了多個類,那麼其尋找方法的方式有兩種,分別是 深度優先 經典類 和廣度優先 新式類 class 經典類 唯一的區...
使用反射進行物件例項化
使用反射進行物件例項化 使用反射進行物件例項化,不再使用new關鍵字 1.第一種,使用.properties配置檔案建立物件 首先需要乙個實體類 public class phone 接下來新建乙個資料夾rescources,在裡面建立檔案phone.properties myphone是後面get...
《 Python 機器學習專題手冊》筆記 3
import numpy as np from sklearn import preprocessing data np.array 3,1.5,2,5.4 0,4,0.3,2.1 1,3.3,1.9,4.3 去除均值 data standardized preprocessing.scale da...