国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設計 > 正文

委托是什么

2019-11-14 16:29:29
字體:
來源:轉載
供稿:網(wǎng)友

目前大部分文章關注是如何使用委托?為什么要使用委托?
卻很少關注委托是什么?委托是如何工作的?明白這兩個問題能幫助我們更好的理解使用委托。
本文的內容 就是針對這兩個問題。

先看一個最簡單的例子

 1     class PRogram 2     { 3         delegate void TestDelegate(int val); 4         static void Main(string[] args) 5         { 6             TestDelegate Dele = new TestDelegate(Fun1); 7             Dele += new Program().Fun2; 8  9             Dele(2);10 11             Console.ReadKey();12         }13 14         static void Fun1(int a)15         {16             Console.Write(a);17         }18         void Fun2(int b)19         {20             Console.Write(b);21         }22     }

這是我們看到的代碼,對于委托只有一句:

 delegate void TestDelegate(int val);

或許不太好理解 委托到底是什么。

那么我們看IL代碼,圖1:

 

我們可以看到
  命名空間 MyProject 下包含 類型 MyProject.Program

類型MyProject.Program 下分別包含:

一個類型 TestDelegate,正是我們聲明的委托。
構造函數(shù):.ctor
靜態(tài)方法:Fun1
實例方法:Fun2
程序入口:Main 

由此,我們可以知道 我們聲明的委托TestDelegate是被編譯成類型的。
然后在看其內部信息:
  繼承自System.MulticastDelegate
  構造函數(shù):.ctor
  異步方法:BeginInvoke,EndInvoke,
  常規(guī)調用方法:Invoke

    其中,System.MulticastDelegate 繼承自 System.Delegate。

理清上面的關系,并且把各繼承類中主要成員提取出來,于是我們上面的代碼實際是這個樣子:

 1 class Program 2     { 3         /// <summary> 4         /// 委托類型,實際上System.Delegate提供了很多成員,這里只列出主要的成員。 5         /// </summary> 6         public sealed class TestDelegate 7         { 8             private object _invocationList;//Obiect類型,System.MulticastDelegate成員,委托列表,無委托列表時為null,創(chuàng)建委托列表時值為 Delegate[] 9             private object _target;//Object類型,System.Delegate成員,當以實例方法創(chuàng)建委托時,保存該實例方法的對象。當以靜態(tài)方法創(chuàng)建委托時,指向當前委托對象.10             private System.IntPtr _methodPtr;//IntPtr類型,System.Delegate成員,當以實例方法創(chuàng)建委托時,保存該實例的方法引用,運行時是該方法的內存地址。11             private System.IntPtr _methodPtrAux;//IntPtr類型,System.Delegate成員,當以靜態(tài)方法創(chuàng)建委托時,保存靜態(tài)的方法引用,運行時是該方法的內存地址。12             public System.Reflection.MethodInfo Method;//只讀屬性,返回System.Reflection.MethodInfo對象,其中包含_methodPtr或_methodPtrAux指向的方法(即注冊委托的方法)的相關信息。13             public object Target;//只讀屬性,實例方法創(chuàng)建委托 返回_target,靜態(tài)方法創(chuàng)建委托 返回null,14             ///以下主要方法的實現(xiàn)以文字描述,也方便理解。本已寫了部分偽代碼,但有些操作是編譯器實現(xiàn)的,偽代碼也不好寫。所以文字描述。15             16             /// <summary>17             /// 構造函數(shù),創(chuàng)建委托實例            18             /// </summary>19             /// <param name="target"></param>20             /// <param name="method"></param>21             protected TestDelegate(object target, string method) 22             {23                 //委托類的構造函數(shù)接受兩個參數(shù),但實際上我們創(chuàng)建的時候只傳遞了一個方法引用,為什么?        24                 //實際上編譯器 會分析我們傳入的參數(shù),將類型的對象引用傳遞給target,方法引用傳遞給method.25                 初始化_invocationList==null;26         27                 當為實例方法時:28                     傳遞target 給_target29                     傳遞method給_methodPtr30         31                 當為靜態(tài)方法時:32                     傳遞當前委托對象給_target,但此時訪問屬性Target時,返回null33                     method傳遞給_methodPtrAux    34             }35             /// <summary>36             /// 添加委托37             /// </summary>38             /// <param name="a"></param>39             /// <param name="b"></param>40             /// <returns></returns>41             public static Delegate Combine(Delegate a, Delegate b) 42             {43                 如果 a 和b 都為null ,拋異常44                 如果a==null,返回b,b==null,返回a45                 否則,合并a和b的委托列表(_invocationList),傳遞給b,返回b ;合并后,a委托列表在前,b委托列表在后           46             }   47             /// <summary>48             /// 刪除49             /// </summary>50             /// <param name="source"></param>51             /// <param name="value"></param>52             /// <returns></returns>53             public static Delegate Remove(Delegate source, Delegate value)54             {55                 獲取source._invocationList56         57                 如果source._invocationList 中包含value._invocationList58                     從source._invocationList中移除 value._invocationList59                     返回source60         61                 如果value==null 或 source._invocationList 中不包含value._invocationList62                     返回source63         64                 如果source==null 或 source._invocationList ==value._invocationList 65                     返回null66             }67             /// <summary>68             /// 調用69             /// </summary>70             /// <param name="value"></param>71             public void Invoke(int value)72             {73                 如果_invocationList為null,執(zhí)行 _methodPtr.Invoke(_target,value)74                 否則,遍歷_invocationList(其值為Delegate[]),調用每一個委托75             }76         }77         static void Main(string[] args)78         {79             TestDelegate Dele = new TestDelegate(Fun1);//調用構造函數(shù),F(xiàn)un1為靜態(tài)方法,此時 Dele._target指向Dele自身80             Dele += new Program().Fun2;//Fun2為實例方法,此時此時 Dele._target指向new Program()對象81             //對于這一步的+=操作的具體步驟是:(注:編譯器自動對委托實例重載了+=,-=操作,-=同理)82             //1、 new Program(),并獲取該對象Fun2方法的引用;靜態(tài)方法時,直接獲取方法引用。83             //2、 new TestDelegate(),傳入第一步方法引用為構造函數(shù)參數(shù)。84             //3、 調用Combine方法。參數(shù)分別為Dele和第二步的委托對象。85             86             Dele(2);//調用Invoke方法87             Console.ReadKey();88         }89         static void Fun1(int a)90         {91             Console.Write(a);92         }93         void Fun2(int b)94         {95             Console.Write(b);96         }97     }

 

委托的實質是一個類,其內部 維護了注冊方法的 類型引用,方法引用及本身的委托列表等成員。
并提供了構造,添加,刪除,調用等方法。最大的特色是可以對按順序 調用 委托列表的中注冊方法。

 

然后再來看事件
在上部分代碼基礎上添加事件。

 1     class Program 2     { 3         public delegate void TestDelegate(int val); 4         public event TestDelegate TestEvent; 5         static void Main(string[] args) 6         { 7             Program p = new Program(); 8             p.TestEvent += p.Fun2; 9             p.TestEvent += Program.Fun1;10             p.TestEvent(3);11             Console.ReadKey();12         }13         static void Fun1(int a)14         {15             Console.Write(a);16         }17         public void Fun2(int b)18         {19             Console.Write(b);20         }21     }

直接看IL

主要成員:

1、名為TestEvent的私有TestDelegate對象
2、添加事件方法:add_TestEvent(TestDelegate value),參數(shù)為TestDelegate類型
3、刪除事件方法:remove_TestEvent(TestDelegate value),參數(shù)為TestDelegate類型

 

對于添加操作TestEvent+=Fun2實際會做以下操作(刪除同理):
1、獲取Fun2引用(同委托獲取引用)。
2、new TestDelegate(),并傳入第一步引用為參數(shù)。
3、調用add_TestEvent方法,參數(shù)為上一步創(chuàng)建的TestDelegate實例。
4、在add_TestEvent方法內部,通過調用System.Delegate.Combine(Delegate a, Delegate b)方法,將第二步對象加入TestEvent對象委托列表 

 

在上述實例中就是在 Program對象 內部提前創(chuàng)建了一個私有TestDelegate委托對象TestEvent,并對其提供了 添加和刪除 TestDelegate對象的方法。

事件的添加,刪除,調用就是對TestEvent對象的添加,刪除,調用。

可以看出 所謂事件只是對委托做了簡單的包裝。其本質依然是委托。

對于常用的標準事件的寫法 public event EventHandler<EventArgs> TestEvent, 原理也如此,區(qū)別只是注冊方法的參數(shù)不同而已。

 


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 梁河县| 玉门市| 隆化县| 长沙县| 余庆县| 维西| 吉木萨尔县| 原平市| 通海县| 九江市| 兴城市| 渭源县| 台东市| 香格里拉县| 遂溪县| 晋中市| 抚远县| 泸溪县| 铁岭市| 怀远县| 荆州市| 井冈山市| 江油市| 桑植县| 蓬溪县| 二连浩特市| 罗田县| 天台县| 兴隆县| 南召县| 珲春市| 蒲江县| 栖霞市| 崇左市| 静海县| 柳河县| 富平县| 皋兰县| 阿拉尔市| 张家川| 五大连池市|