动态调用对象的属性和方法——性能和灵活性兼备的方法
在動(dòng)態(tài)編程時(shí),我們常常需要運(yùn)行時(shí)確定調(diào)用對(duì)象的哪個(gè)屬性或哪個(gè)方法。這個(gè)任務(wù)通常可以用反射來解決。但眾所周知,反射的性能要比靜態(tài)指定的方式低很多,因?yàn)榉瓷湟ㄟ^運(yùn)行時(shí)復(fù)雜的機(jī)制完成。能否獲得性能和靈活性兼?zhèn)涞膭?dòng)態(tài)調(diào)用?我在開發(fā)VBF的最新功能時(shí)反復(fù)考慮了這個(gè)問題。我們通常動(dòng)態(tài)調(diào)用一個(gè)對(duì)象的屬性是采用這樣的手法,假設(shè)對(duì)象a有一個(gè)屬性叫做MyProp:
Type t = a.GetType();
PropertyInfo pi = t.GetProperty("MyProp");
string value = (string)pi.GetValue(a, null);
注意到什么問題了嗎?我們知道這個(gè)屬性的類型是string,也知道它沒有參數(shù)。當(dāng)然也有不知道即將調(diào)用的屬性類型及參數(shù)的時(shí)候,但這個(gè)場(chǎng)合我們知道,卻沒有利用,還是當(dāng)成什么信息都不知道一樣使用純動(dòng)態(tài)的手法獲取。這樣我們就錯(cuò)失了能利用強(qiáng)類型特性加速這一過程的良機(jī)。同樣還有方法調(diào)用,我們有時(shí)候只是方法或?qū)傩缘拿衷诰幾g時(shí)不知道(比如需要用戶指定),但方法或?qū)傩缘念愋图昂灻覀兪侵赖?#xff0c;這種情況下就可以用泛型和委托技術(shù)高性能地調(diào)用。
泛型技術(shù)為處理類型提供了方便,除此之外,.NET的委托還具有一些額外的良好特性。委托可以擔(dān)當(dāng)類似接口的任務(wù),但與接口最大的不同就在于,方法無須聲明自己滿足某個(gè)委托,而只要簽名符合,即可賦給委托變量。這樣我們就可以利用一組事先聲明的委托,處理千變?nèi)f化類型的屬性與方法。
C#不允許屬性帶有參數(shù),除非是索引器。VB允許屬性帶有參數(shù)但很少有人真的大量使用。于是在真實(shí)世界中屬性的getter和setter的形式就被限定了,絕大部分屬性的getter和setter可以用以下兩個(gè)委托表示:
public delegate void PropertySetter<T>(T value);
public delegate T PropertyGetter<T>();
有了這兩個(gè)委托,我們就可以對(duì)已知類型但名字需要?jiǎng)討B(tài)化的屬性進(jìn)行高速的強(qiáng)類型動(dòng)態(tài)訪問了。方法是使用反射獲取屬性Gettet或Setter的MethodInfo,再使用MethodInfo創(chuàng)建委托:
Type t = a.GetType();
PropertyInfo pi = t.GetProperty("MyProp");
MethodInfo getter = pi.GetGetMethod();
PropertyGetter<string> strPropGetter =
???(PropertyGetter<string>)Delegate.CreateDelegate( 
?? typeof(PropertyGetter<string>), a, getter);
string value = strPropGetter();
注意,這個(gè)方法在調(diào)用前進(jìn)行了更多反射操作,因此,如果你只想一兩次地獲取屬性的值,這種方法還不如直接用放射來的快。但是,當(dāng)你需要對(duì)同一屬性進(jìn)行成千上萬次訪問時(shí),絕對(duì)值得多寫這點(diǎn)代碼,在string類型的簡單屬性上,速度可比直接反射獲取最多快達(dá)1000倍,這是我實(shí)測(cè)的結(jié)果。
接下來我們討論有index的屬性和方法的調(diào)用。C#盡允許在索引器的語法上使用屬性參數(shù),而在VB看來,索引器不過是類所有帶參數(shù)的屬性中比較特殊的一個(gè),他得到了在對(duì)象上使用數(shù)組語法訪問的特權(quán)。不管怎么說,無論是索引器還是普通帶參數(shù)的屬性,他們的getter和setter過程都不像典型屬性那樣簡單。同樣還有對(duì)方法的調(diào)用,方法的簽名千變?nèi)f化,似乎我們很難用預(yù)先定義的委托統(tǒng)一進(jìn)行調(diào)用。事實(shí)的確如此,不過與針對(duì)每一種屬性訪問器或方法的簽名定義一種委托的做法相比,泛型還是給出了一種稍微舒服一點(diǎn)的做法:
public delegate R Func<R>();
public delegate R Func<T0, R>(T0 a0);
public delegate R Func<T0, T1, R>(T0 a0, T1 a1);
public delegate R Func<T0, T1, T2, R>(T0 a0, T1 a1, T2 a2);
這樣一組泛型委托,可以涵蓋參數(shù)數(shù)目從0-3,有返回值并且沒有參數(shù)是out或ref的所有方法簽名。你還可以定義一組用于無返回值的。有了這樣一組泛型委托,就可以在想要某種函數(shù)的簽名時(shí)直接創(chuàng)建出來,而無須聲明新的類型。再結(jié)合剛才的手法,就可以用統(tǒng)一的手法實(shí)現(xiàn)大部分帶有參數(shù)的屬性或方法的動(dòng)態(tài)調(diào)用——同時(shí)獲得動(dòng)態(tài)名稱和強(qiáng)類型性能的雙重好處。
也許你早已經(jīng)利用了類似的手法,并用于除了動(dòng)態(tài)調(diào)用屬性或方法以外的其他任務(wù)。我只是在開發(fā)VBF時(shí)想到了他們,希望能對(duì)部分需要的人有所幫助。
轉(zhuǎn)載于:https://www.cnblogs.com/Ninputer/archive/2006/01/08/313266.html
總結(jié)
以上是生活随笔為你收集整理的动态调用对象的属性和方法——性能和灵活性兼备的方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: 关联表多数据的批量insert (批量导
 - 下一篇: MySQL通过source命令执行sql