C#委托與事件的本質區別


  從定義上說,委托被編譯器編譯成一個類,所以它可以像類一樣在任何地方定義,而事件被編譯成一個委托類型的私有字段和兩個公有add 和 remove 方法(有點類似於屬性的定義)不過這兩個方法都有一個參數,這個參數就是委托,所以,它只能定義在一個類里面。

   從定義可知,委托是要是需要實例化的,它4個方法:一個構造器,Invoke,BeginInvoke和EndInvoke。構造器有兩個參數分別是:一個對象引用,另一個是引用回調方法的一個IntPtr。然而實例化委托的代碼的參數只是一個方法的引用。但這不是問題,編譯器明白這其中的一切會獲取對應的參數。然而事件是不需要實例化的因為他只是一個字段和兩個方法,只是類的一些成員,但是可以初始化,通過一些賦值操作!

    實例化委托時,定義他參數的方法的參數及返回類型必須符合委托的Invoke參數及返回類型,而事件被定義后,它可以通過方法所在類的對象調用add方法來添加一個委托和remove方法來移除一個委托!而兩個方法的結果是返回一個委托引用並賦值給事件定義生成的私有委托字段,如果是多次調用就返回一個委托列表頭的引用。而傳入的這個參數即是由要觸發的方法而封裝的委托。(參數為什么是委托而不直接傳入一個方法引用呢,這樣效率不是更高嗎)因為委托是調用回調方法的一種類型安全的方式。通過add方法即是訂閱了一個事件,然后就是觸發事件了,即通過點擊按鈕等輸入操作即可觸發事件,然后調用私有的委托變量,然后即像調用委托一樣,調用他的Invoke方法即引用定義的方法的地址來執行該方法,然后這個事件就結束了。

  總結:事件的訂閱分兩個階段:首先是傳入的參數(即委托)的實例化,相當於委托的實例化,調用該委托的構造函數(一個對象引用,一個IntPtr類型的回調方法的引用),其次就是委托鏈(也即多播委托)的構建過程,第一次訂閱是用一個null和傳入的委托的Combine,此時直接返回傳入的委托地址,如果第二次訂閱就會構造一個新的委托對象,_invocationList字段被初始化為一個委托對象數組,引用兩個委托地址,最后返回這個新建的對象地址,以后依此類推。

  接下來就是事件的觸發階段了,通過鼠標單擊或動態用代碼去實現,其本質只有一個步驟即委托的調用,如果只有一個委托,直接調用Invoke方法,如果有多個委托,即發現_invocationList不為null,會循環調用數組里的所有元素,每個元素的實現即為只有一個委托時調用的Invoke方法。

    簡而言之,即事件分為兩個階段一個是委托的實例化(對應事件訂閱),一個是委托的調用(對應事件觸發)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM