2023-06-25 15:02:14 來源 : 博客園
委托(delegate
)是一種特殊的類型(class
),它可以被認(rèn)為是一個(gè)可以擁有函數(shù)引用的類,它的聲明規(guī)定了它能夠持有的函數(shù)引用的函數(shù)形式,同時(shí)它可以存儲(chǔ)多個(gè)函數(shù)引用,并通過自己的方法調(diào)用所有注冊在它身上的方法(發(fā)布者)。
(相關(guān)資料圖)
理解了觀察者模式就理解了委托
它的特點(diǎn)在于:
委托類型的定義方式通過特定關(guān)鍵字delegate
來定義,而不是 class
我們無法為委托類型定義方法,它繼承固定的類有固定的方法,這是發(fā)生在語言底層的一個(gè)委托類型的變量時(shí)可以像一個(gè)普通類型的變量一樣聲明,但更好的方式是使用 event
關(guān)鍵字來修飾委托類型的變量,event
關(guān)鍵字包裝了委托類型的變量(事件變量不是委托變量,它們是兩個(gè)東西,盡管它們在聲明方式上很像,事件變量包裝了一個(gè)委托變量),這將避免從類外控制這個(gè)事件的發(fā)布(Invoke
)namespace InterfaceTest{ [TestClass] public class DelegateTest { // 一個(gè)自定義的委托類型的變量,類比自定義的類的變量 public event Function calc; [TestMethod] public void TestMethod1() { calc += () => { return 0.0; }; calc += DelegateTest.C; calc += new Function(C); calc = calc + C; calc.Invoke(); } public static double C() { return 1.0; } } // 委托是一個(gè)類型,所以它可以直接定義在名稱空間下 // 無法為委托類型自定義方法 public delegate double Function(); public class Caller { public Caller() { var dt = new DelegateTest(); // 由于calc是一個(gè)event修飾的屬性,所以從外部調(diào)用Invoke將引發(fā)異常 dt.calc.Invoke(); // ERROR } }}
就像我們可以直接使用語言本身提供的 string
類型一樣,我們也可以直接使用語言本身提供的 Action
和 Func
委托類型,它們已經(jīng)包含了絕大多數(shù)可能的函數(shù)簽名的形式,而無需自定義自己的 “MyString”
委托及觀察者模式在觀察者模式中主要有四個(gè)事物:發(fā)布者、訂閱者、“訂閱”過程、“發(fā)布”過程。
發(fā)布者主要包含一個(gè)保存了訂閱者引用的集合,在“發(fā)布過程”發(fā)生時(shí),通過這個(gè)訂閱者所持有的引用調(diào)用實(shí)現(xiàn)了相同接口的訂閱者的方法(在這一步有多種方式,不一定非要是接口,目的在于使發(fā)布者能夠通過多態(tài)統(tǒng)一保存所有的訂閱者,從而在“發(fā)布”時(shí)遍歷整個(gè)集合調(diào)用所有訂閱者的方法。關(guān)于其它的實(shí)現(xiàn)方式可見引用.6)。
在委托中,觀察者模式的這四個(gè)部分的實(shí)現(xiàn)如下:
發(fā)布者:委托類型的變量
訂閱者:符合委托類型定義的函數(shù)簽名的函數(shù),表現(xiàn)形式有l(wèi)ambda表達(dá)式、直接定義的函數(shù)等(將函數(shù)當(dāng)作一個(gè)函數(shù)類型的實(shí)例)
“訂閱”:+
-
,常見的形式是 +=
-=
,本質(zhì)上是委托類型重載了 +
和 -
運(yùn)算符
“發(fā)布”:
由系統(tǒng)負(fù)責(zé)“發(fā)布”,程序員提供發(fā)布時(shí)的動(dòng)作(委托類型的函數(shù)):例如,WPF或Winform后置代碼中的事件響應(yīng)函數(shù)
由程序員負(fù)責(zé)“發(fā)布”,系統(tǒng)負(fù)責(zé)提供發(fā)布時(shí)的動(dòng)作:例如,WPF中的OnPropertyChanged
在ViewModel中手動(dòng)調(diào)用,但它上的函數(shù)的注冊在XAML解析時(shí)完成