程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 再議C#方法中的反射方式和委托方式

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

編輯:C#入門知識

 在開發過程中對靜態方法的調用是通過類型名後面加個點而後是調用方法的名稱,對類型實例方法的調用是通過new一個對象,而後點加方法名稱,這是最熟悉不過的兩種方式。還可以通過讀取CLR元數據,利用反射進行方法調用。在利用反射方式調用方法時,最重要的兩個類是System.Type和System.Reflection.MethodInfo.用MethodInfo類型的Invoke方法調用方法,必須傳入目標對象實例的引用。如下:
  publicclassCalculate { //使用反射可以調用私有方法private intAdd(intleftNum, intrightNum)
  { returnleftNum + rightNum;} classProgram { staticvoidMain(string[] args)
  { //用type.getmethod的方法獲取類型方法,BindingFlags設置查找方法的范圍//本例是公有方法,私有方法而且是非靜態的才被查找,如果要查找靜態方法//需要設置BindingFlags.Static MethodInfomethod = typeof(Calculate)。GetMethod("Add", BindingFlags.Public | BindingFlags.NonPublic |BindingFlags.Instance);if(method == null) return //調用方法的參數object[] paras ={ 10, 20 };//目標對象實例:new Calculate()
  objectresult = method.Invoke(newCalculate(), paras);Console.WriteLine(result);Console.ReadLine();}委托方式
  任何對象都可以調用委托,只要方法返回值以及方法簽名和委托聲明一樣就行。


 
  通過閱讀CLR源代碼,整理了委托類的重要字段和幾個常用方法,自定義的委托類型都派生於MulticastDelegate.
  publicabstractclassDelegate: ICloneable,ISerializable { // 調用目標對象,實例方法為類型實例引用,靜態方法則為null internalObject_target;//指向調用方法internalIntPtr_methodPtr;//委托構造器protectedDelegate(Objecttarget, Stringmethod)
  { //省略,具體看以查看clr源代碼} publicstaticDelegateCreateDelegate(Typetype, Objecttarget, Stringmethod)
  { //省略,具體看以查看clr源代碼} publicstaticDelegateCreateDelegate(Typetype, Typetarget, Stringmethod)
  { //省略,具體看以查看clr源代碼} publicstaticDelegateCombine(paramsDelegate[] delegates) {} publicstaticDelegateCombine(Delegatea, Delegateb) {} publicstaticDelegateRemove(Delegatesource, Delegatevalue){} } publicabstractclassMulticastDelegate: Delegate { privateObject_invocationList;protectedMulticastDelegate(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;} classProgram { 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));Console.ReadLine();} CreateDelegate需要通過遍歷元數據來獲取方法句柄。C#語法提供了更便利的方法來調用委托,可以簡單通過類型名或者對象名來限定方法,而且不需要通過遍歷元數據,C#編譯器使用底層CIL的ldftn或許ldvirtftn操作符獲取方法地址,相對來說要比CreateDelegate快的多了。上面的Main方法可以改寫為
  staticvoidMain(string[] args)
  { DelegateCaculateadd = newDelegateCaculate(newCaculate()。Add);DelegateCaculatesubtract = newDelegateCaculate(Caculate.Subtract);Console.WriteLine("add:"+ add(10, 20));Console.WriteLine("subtract:"+ subtract(10, 20));Console.ReadLine();}可以將多個委托對象放到委托對象數組中,一旦對其調用,CLR將遍歷委托數組,對其逐一調用。
  publicdelegatevoidDelegateCaculate(inta,intb);publicclassCaculate { publicstaticvoidAdd(intnum1, intnum2)
  { Console.WriteLine((num1+ num2));} publicstaticvoidSubtract(intnum1, intnum2)
  { Console.WriteLine((num2- num1));} classProgram { staticvoidMain(string[] args)
  { DelegateArray(newDelegateCaculate(Caculate.Add), newDelegateCaculate(Caculate.Subtract));Console.ReadLine();} staticvoidDelegateArray(DelegateCaculatea, DelegateCaculateb)
  { DelegateCaculatedelChain = null delChain = (DelegateCaculate)Delegate.Combine(delChain, a);delChain = (DelegateCaculate)Delegate.Combine(delChain, b);delChain(10, 20);} C#提供了更便捷的語法把委托對象添加到委托數組內,可以這樣修改上面的DelegateArray方法,
  staticvoidDelegateArray(DelegateCaculatea, DelegateCaculateb)
  { DelegateCaculatedelChain = null delChain += a;delChain+=b;delChain(10, 20);}當執行(DelegateCaculate)Delegate.Combine(delChain, a)時,因為委托數組中只有一個a對象,所以delChain也只是簡單的指向a.示意圖如下


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

 
  如果還有委托對象加入,將會再次生成一個新的MulticastDelegate對象讓delChain指向這個新對象,原來的對象則等待垃圾回收器進行回收,這點可以查看CLR源代碼,每添加一個委托對象就調用一次方法NewMulticastDelegate,這個方法返回值是MulticastDelegate.
  委托與接口
  接口與委托都擁有調用特定方法的能力,所以他們在這點很相像。但是接口需要目標方法的類型聲明必須與該接口兼容,而委托可以被任何類型調用,只要該類型的目標方法簽名和委托簽名匹配即可。
  那麼何時用委托,何時用接口呢,msdn 總結的非常好,我就直接給粘貼過來了,
  委托在以下情況很有用:
  1、 調用單個方法。
  2、 一個類希望有方法規范的多個實現。
  3、 希望允許靜態方法實現規范。
  4、 希望類似事件的設計模式。
  5、 調用方不需要知道或獲得實現與委托簽名匹配的方法的對象。
  6、 實現的提供程序希望只對少數選擇組件“分發”規范實現。
  7、 需要方法的組合。
  接口在以下情況很有用:
  1、 規范定義一組相關方法。
  2、 類通常只實現規范一次。
  3、 接口的調用方希望轉換為接口類型或從接口類型轉換,以獲得其他接口或類。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved