摘 要:在C#里,委托與事件類是兩個不易理解的概念。主要闡述對委托與事件的理解,同時結合Observer設計模式與.NET Framework規范,針對生活中的案例來辨析委托與事件的應用。
關鍵詞:委托;事件Observer設計模式;.NET Framework
中圖分類號:TP 文獻標識碼:A 文章編號:1672-3198(2010)06-0284-02
C#中的委托類似于C++中的函數指針,功能卻更多。事件是在委托的基礎上的一種結構,類似于委托的變量,在界面的控件中處處都有應用。
1 什么是委托
委托的申明格式:修飾符 delegate 返回值數據類型 委托名(形參列表)。
例如:Delegate int AbcDel(string s, bool b);是一個委托申明,每一個委托都有自己的簽名,就是說AbcDel這個委托有string 和bool類型的形參,返回一個int類型數據,即具有這樣的函數簽名。委托類似于函數指針,它能夠引用函數,通過傳遞地址的機制完成。委托是一個類,當對它實例化時,要提供一個引用函數,將其作為它構造函數的參數。例如:private int AbcFun (string str, bool bln){},則可以把這個函數傳給AbcDel的構造函數,因為它們簽名一致。AbcDel sd = new SomeDelegate(AbcFun),sd 引用了 AbcFun,也就是說,AbcFun已被sd所登記注冊,如果你調用sd,AbcFun這個函數即會被調用。
2 事件的理解
事件的申明格式:修飾符 event 委托名 事件名;
例如:public event AbcDel Boil;//AbcDel為委托名
Boil事件的聲明與之前委托變量sd的聲明唯一的區別是多了event關鍵字。聲明事件類似于聲明一個委托類型的變量。
3 Observer設計模式
假設熱水器系統由兩部分組成:熱水器、警報器,由不同廠商進行了組裝。熱水器僅負責燒水;警報器在水燒開時發出警報,當水溫超過95度,就發出警報。我們需要應用委托與事件來模擬此過程。
Observer設計模式是為了定義對象間的一種一對多的依賴關系,以便于當一個對象的狀態改變時,其他依賴于它的對象會被自動告知并更新。Observer模式是一種松耦合的設計模式。它包括兩類對象:
Subject:監視對象,它包含其他對象感興趣的內容。熱水器是一個監視對象,它包含temprature字段,當它>95時,會不斷把數據發給監視它的對象。
Observer:監視者,它監視Subject,當Subject中的某件事發生時,會告知Observer,Observer即采取相應行動。Observer就是警報器。
在本例中,事情發生的順序如下:
警報器告訴熱水器,它對它的溫度感興趣(注冊)。
熱水器知道后保留對警報器的引用。
熱水器進行燒水這一動作,當水溫超過95度時,通過對警報器的引用,自動調用警報器的MakeAlert()方法。代碼如下:
Heater類:
private int temperature;
public delegate void BoilHandler(int param);//聲明委托
public event BoilHandler BoilEvent; //聲明事件
public void BoilWater() { for (int i = 0; i <= 100; i++) { temperature = i; // 燒水
if (temperature > 95) {if (BoilEvent != 1) {//如果有對象注冊
BoilEvent(temperature) ;} } }//調用所有注冊對象的方法
Alarm類:public void MakeAlert(int param) {//…輸出水溫 }
主函數主要代碼如下:
heater.BoilEvent += alarm.MakeAlert;//注冊方法
heater.BoilWater();//燒水,會自動調用注冊過的方法
輸出:Alarm:嘀嘀嘀,水已經96度了:
Alarm:嘀嘀嘀,水已經97度了:// ...
4 Net Framework中的委托與事件
上面的代碼很好地完成了工作,但.Net Framework中事件模型有所不同,.Net Framework的編碼規范如下:
(1)委托類型名稱都以EventHandler結束;
(2)委托的原型定義:返回值void,接受兩個輸入參數:一個Object 類型,一個EventArgs類型(或繼承自EventArgs,但類型名要以EventArgs結尾);
(3)事件的命名:委托去掉EventHandler之后剩余的部分。
委托聲明原型中的Object類型的參數代表了Subject,即監視對象,在本例中是Heater。回調函數(Alarm的MakeAlert)可以通過它訪問觸發事件的對象(Heater)。EventArgs對象包含了Observer感興趣的數據,即temperature。
上面這些不僅是為了編碼規范,也使程序更靈活。將熱水器的引用傳給警報器的方法,就可以直接訪問熱水器的溫度、型號等。按.Net Framework改寫此例:
Heater類代碼如下:
public string type = “RealFire 001”;//型號
public delegate void BoiledEventHandler(Object sender, BoliedEventArgs e);
public event BoiledEventHandler Boiled;
public class BoliedEventArgs : EventArgs { //定義BoliedEventArgs類,
public readonly int temperature;//傳遞給observer所感興趣的信息
public BoliedEventArgs(int temperature) {this.temperature = temperature; }}
protected virtual void OnBolied(BoliedEventArgs e) {
if (Boiled != 1) { Boiled(this, e); // 調用所有注冊對象的方法 } }
public void BoilWater() {
for (int i = 0; i <= 100; i++) {temperature = i; if (temperature > 95) {
BoliedEventArgs e = newBoliedEventArgs(temperature);OnBolied(e); }}}
Alarm類代碼如下:
public void MakeAlert(Object sender, Heater.BoliedEventArgs e) {
Heater ht = (Heater)sender;Console.WriteLine(“Alarm:{0},嘀嘀嘀,水已經{1}度了!”, ht.type,ht.temperature) ;}//訪問公共字段
主函數除了事件名有所改變,其它代碼同上。
輸出為:Alarm:RealFire 001,嘀嘀嘀,水已經96度了!//省略..
5 結束語
在本文中我首先說明了我對委托與事件的理解。接下來通過一個熱水器系統的范例,結合Observer設計模式中與委托、事件,用代碼實現了這個例子,隨后結合此例講述了.Net Framework中委托、事件的實現方式。
參考文獻
[1]譚浩強.C++語言程序設計[M].北京:清華大學出版社,2006.
[2](美)Stephen C.Perry 著,肖斌,王小振等譯.C#和.NET核心技術[M]. 北京:機械工業出版社,2007,(3).