天天看點

再議C#方法中的反射方式和委托方式再議C#方法中的反射方式和委托方式

我們将要談到的是C#方法中的反射方式和委托方式,文中還将給出具體代碼,以友善大家測試和實踐。

AD:

在開發過程中對靜态方法的調用是通過類型名後面加個點而後是調用方法的名稱,對類型執行個體方法的調用是通過new一個對象,而後點加方法名稱,這是最熟悉不過的兩種方式。還可以通過讀取CLR中繼資料,利用反射進行方法調用。在利用反射方式調用方法時,最重要的兩個類是System.Type和System.Reflection.MethodInfo。用MethodInfo類型的Invoke方法調用方法,必須傳入目标對象執行個體的引用。如下:

public class Calculate  

{  

//使用反射可以調用私有方法  

private intAdd(int leftNum, int rightNum)  

return leftNum + rightNum;  

}  

 }  

classProgram  

static voidMain(string[] args)  

//用type.getmethod的方法擷取類型方法,BindingFlags設定查找方法的範圍  

//本例是公有方法,私有方法而且是非靜态的才被查找,如果要查找靜态方法  

//需要設定BindingFlags.Static  

MethodInfo method = typeof(Calculate).GetMethod("Add", BindingFlags.Public  

| BindingFlags.NonPublic  

|BindingFlags.Instance);  

if(method == null) return 

//調用方法的參數  

object[] paras ={ 10, 20 };  

//目标對象執行個體:new Calculate()  

objectresult = method.Invoke(new Calculate(), paras);  

Console.WriteLine(result);  

Console.ReadLine();  

委托方式

任何對象都可以調用委托,隻要方法傳回值以及方法簽名和委托聲明一樣就行。

再議C#方法中的反射方式和委托方式再議C#方法中的反射方式和委托方式

通過閱讀CLR源代碼,整理了委托類的重要字段和幾個常用方法,自定義的委托類型都派生于MulticastDelegate。

public abstract class Delegate: ICloneable,ISerializable  

// 調用目标對象,執行個體方法為類型執行個體引用,靜态方法則為null  

internalObject_target;  

//指向調用方法  

internalIntPtr_methodPtr;  

//委托構造器  

protected Delegate(Objecttarget, Stringmethod)  

//省略,具體看以檢視clr源代碼  

public static Delegate CreateDelegate(Typetype, Objecttarget, Stringmethod)  

public static Delegate CreateDelegate(Typetype, Typetarget, Stringmethod)  

public static Delegate Combine(paramsDelegate[] delegates) {}  

public static Delegate Combine(Delegatea, Delegateb) {}  

public static Delegate Remove(Delegatesource, Delegatevalue){}  

public abstract class MulticastDelegate: Delegate  

private Object _invocationList;  

protected MulticastDelegate(Objecttarget, Stringmethod) : base(target, method) { }  

protectedMulticastDelegate(Typetarget, Stringmethod): base(target, method) { }  

從源代碼可以看出Delegate類提供了幾個重載的靜态方法CreateDelegate,方法傳回值是Delegate類型。如果是執行個體方法則把對象引用傳遞給它,如是靜态方法則傳入對象類型。

publicdelegateintDelegateCaculate(inta,intb);  

publicclassCaculate  

publicintAdd(intnum1, intnum2)  

returnnum1 + num2;  

publicstaticintSubtract(intnum1, intnum2)  

 returnnum2 - num1;  

 {  

staticvoidMain(string[] args)  

Caculatecaculate = newCaculate();  

TypetypeCaculate = typeof(Caculate);  

TypetypeDelegate = typeof(DelegateCaculate);  

DelegateCaculateadd = (DelegateCaculate)Delegate.CreateDelegate(typeDelegate, caculate, "Add");  

DelegateCaculatesubtract = (DelegateCaculate)Delegate.CreateDelegate(typeDelegate, typeCaculate, "Subtract");  

Console.WriteLine("add:"+ add(10, 20));  

Console.WriteLine("subtract:"+ subtract(10, 20));  

CreateDelegate需要通過周遊中繼資料來擷取方法句柄。C#文法提供了更便利的方法來調用委托,可以簡單通過類型名或者對象名來限定方法,而且不需要通過周遊中繼資料,C#編譯器使用底層CIL的ldftn或許ldvirtftn操作符擷取方法位址,相對來說要比CreateDelegate快的多了。上面的Main方法可以改寫為

DelegateCaculateadd = newDelegateCaculate(newCaculate().Add);  

DelegateCaculatesubtract = newDelegateCaculate(Caculate.Subtract);  

可以将多個委托對象放到委托對象數組中,一旦對其調用,CLR将周遊委托數組,對其逐一調用。

publicdelegatevoidDelegateCaculate(inta,intb);  

publicstaticvoidAdd(intnum1, intnum2)  

Console.WriteLine((num1+ num2));  

publicstaticvoidSubtract(intnum1, intnum2)  

Console.WriteLine((num2- num1));  

DelegateArray(newDelegateCaculate(Caculate.Add), newDelegateCaculate(Caculate.Subtract));  

staticvoidDelegateArray(DelegateCaculatea, DelegateCaculateb)  

DelegateCaculatedelChain = null 

delChain = (DelegateCaculate)Delegate.Combine(delChain, a);  

delChain = (DelegateCaculate)Delegate.Combine(delChain, b);  

delChain(10, 20);  

C#提供了更便捷的文法把委托對象添加到委托數組内,可以這樣修改上面的DelegateArray方法,

delChain += a;  

delChain+=b;  

當執行(DelegateCaculate)Delegate.Combine(delChain, a)時,因為委托數組中隻有一個a對象,是以delChain也隻是簡單的指向a。示意圖如下

再議C#方法中的反射方式和委托方式再議C#方法中的反射方式和委托方式

當執行(DelegateCaculate)Delegate.Combine(delChain, b)是,因為委托數組已經有兩個對象了,這時會生成一個新的MulticastDelegate對象讓delChain指向它,而_invocationList指向一個委托數組對象,示意圖如下

再議C#方法中的反射方式和委托方式再議C#方法中的反射方式和委托方式

如果還有委托對象加入,将會再次生成一個新的MulticastDelegate對象讓delChain指向這個新對象,原來的對象則等待垃圾回收器進行回收,這點可以檢視CLR源代碼,每添加一個委托對象就調用一次方法NewMulticastDelegate,這個方法傳回值是MulticastDelegate。

委托與接口

接口與委托都擁有調用特定方法的能力,是以他們在這點很相像。但是接口需要目标方法的類型聲明必須與該接口相容,而委托可以被任何類型調用,隻要該類型的目标方法簽名和委托簽名比對即可。

那麼何時用委托,何時用接口呢,msdn 總結的非常好,我就直接給粘貼過來了,

委托在以下情況很有用:

1、 調用單個方法。

2、 一個類希望有方法規範的多個實作。

3、 希望允許靜态方法實作規範。

4、 希望類似事件的設計模式。

5、 調用方不需要知道或獲得實作與委托簽名比對的方法的對象。

6、 實作的提供程式希望隻對少數選擇元件“分發”規範實作。

7、 需要方法的組合。

接口在以下情況很有用:

1、 規範定義一組相關方法。

2、 類通常隻實作規範一次。

3、 接口的調用方希望轉換為接口類型或從接口類型轉換,以獲得其他接口或類。

原文連結:http://www.cnblogs.com/qiuwuyu/archive/2011/08/29/2157230.html

本文轉自左正部落格園部落格,原文連結:http://www.cnblogs.com/soundcode/archive/2011/10/14/2211409.html,如需轉載請自行聯系原作者

繼續閱讀