學習c#都會驚奇於它的delegate,其實delegate並沒有太多神秘的地方,說的通俗點,delegate是類型化了的函數指針,它主要應用於回調。
學習c++的對函數指針都不回陌生,它是一個保存了函數地址的變量,但除了地址,它沒有包含任何額外的信息,如參數的個數、參數類型和函數的返回地址等,所以函數指針是非類型安全的。而delegate對回調提供了類型的安全性,從而使我們在處理回調等問題的時候可以更加優美的面向對象的方式來編寫代碼,並且在CLR的內部對delegate的操作提供了許多支持(如delegate鏈表),簡化了我們常用的操作。
在使用delegate的過程中,首先要定義一個delegate的類型,如:
public delegate void SomeFunction(Object a,int i,...);
note:它是一個類的定義,可以放在任何地方,此類型定義了此delegate所接收的函數的樣式:返回void,參數列表...
然後,為了使用,要定義類SomeFunction的一個實例:
public SomeFunction instance;
接著,我們就可以往這個delegate實例中放“符合規范”的函數(可以為實例函數和靜態函數)。
instance +=new SomeFunction(someObject.SomeMethod);
其中someObject為某類的一個實例,它的方面SomeMethod符合此委托的規范要求,否則將編譯報錯。
最後,可以直接調用instance實例來實現對someObject的SomeMethod的回調。
instance(...);
##########################
只是從上面的實現中,貌似看不出delegate真正存在的價值,但實際上delegate增加了對鏈的支持,我們可以象下面這樣應用:
instance +=new SomeFunction(someObject.SomeMethod);
instance +=new SomeFunction(anotherObject.anotherMethod);
...
然後調用instance(...),可以同時激發所有注冊自裡面的回調函數。
這是怎樣實現的,首先要研究delegate內在的結構,在每個delegate裡面包括了三個字段:
target ——》指向回調函數所屬的對象實例(對於實例方法來言)
method ——》指向回調函數
prev ——》指向另外一個delegate 實例
通過prev就可以比較方便的實現delegate對鏈的支持。
CLR定義了Delegate.Combine和Delegate.Remove靜態方法實現對鏈表的操作。