原創(chuàng)|其它|編輯:郝浩|2009-04-27 09:59:25.000|閱讀 300 次
概述:在上篇blog中簡單地介紹了委托的基礎(chǔ)知識(shí),在這片文章中會(huì)介紹下委托跟事件之間的聯(lián)系。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
在上篇blog中簡單地介紹了委托的基礎(chǔ)知識(shí),在這片文章中會(huì)介紹下委托跟事件之間的聯(lián)系。
事件的由來
我們可以看到在使用委托進(jìn)行回調(diào)的實(shí)現(xiàn)的時(shí)候,我們往往需要再定義一個(gè)委托對(duì)象,以及一個(gè)對(duì)外公開的輔助方法來添加委托的方法,這樣子會(huì)使我們感覺比較繁瑣。C#提供了event關(guān)鍵字來減輕直接使用委托的負(fù)擔(dān),編譯器會(huì)自動(dòng)提供注冊(cè)、取消注冊(cè)的方法和委托必要的成員。首先來看看定義事件的步驟:
1.先定義委托類型;
2.通過event關(guān)鍵字定委托類型的事件。
public delegate int Caculate(int x, int y); public event Caculate OnCaculate;
看看編譯器幫我們定義了什么
首先我們可以看到幫我們定義了一個(gè)Caculate對(duì)象,其次定義了兩個(gè)方法add_OnCaculate跟remove_OnCaculate。我們可以在看看add_OnCaculate兩個(gè)方法里面的一些核心的東西。add_OnCaculate:
IL_0008: call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate, class [mscorlib]System.Delegate)
很明顯地看到add_OnCaculate方法調(diào)用的就是委托的Combine方法,從而我們也可以想到remove_OnCaculate方法調(diào)用的是Remove方法。從上面我們可以看到其實(shí)event關(guān)鍵字只是提供給我們了一種語法上的便利措施。
一個(gè)稍微完整的例子
這個(gè)例子參考的是《C#與.NET3.0高級(jí)程序設(shè)計(jì)》上面的。使用Car來舉例的,當(dāng)車子加速時(shí)到一定限制值時(shí)會(huì)觸發(fā)一個(gè)預(yù)警事件,當(dāng)超過某一個(gè)速度時(shí)會(huì)觸發(fā)一個(gè)車子爆炸事件。首先看委托跟事件:
public delegate void CarEventHandler(string msg); public event CarEventHandler AbortToBlow; public event CarEventHandler Exploded;
EventCar類中有兩個(gè)事件一個(gè)是AbortToBlow一個(gè)是Exploded。下面是Car的幾個(gè)屬性以及字段:
private const int MaxSpeed = 180; public int CurrSpeed { get; private set; } public bool IsDead { get; private set; } public string Name { get; private set; }
其中IsDead是表示車子是否已經(jīng)報(bào)廢了。下面是一個(gè)加速的方法:
public void Accelerate(int addSpeed) { if (IsDead) { if (this.Exploded!= null) Exploded("The Car Is Dead"); } else { CurrSpeed += addSpeed; if (10 == MaxSpeed - CurrSpeed &&AbortToBlow != null) { AbortToBlow("Careful!Bona blow!"); } if (CurrSpeed >= MaxSpeed) IsDead = true; else Console.WriteLine("CurrentSpeed:{0}", CurrSpeed); } }
完整代碼:
public class EventCar { public delegate void CarEventHandler(string msg); public event CarEventHandler AbortToBlow; public event CarEventHandler Exploded; private const int MaxSpeed = 180; public int CurrSpeed { get; private set; } public bool IsDead { get; private set; } public string Name { get; private set; } public EventCar() { } public EventCar(string carName, int currSpeed) { if (currSpeed > MaxSpeed) IsDead = true; else { Name = carName; CurrSpeed = currSpeed; } } public void Accelerate(int addSpeed) { if (IsDead) { if (this.Exploded!= null) Exploded("The Car Is Dead"); } else { CurrSpeed += addSpeed; if (10 == MaxSpeed - CurrSpeed &&AbortToBlow != null) { AbortToBlow("Careful!Bona blow!"); } if (CurrSpeed >= MaxSpeed) IsDead = true; else Console.WriteLine("CurrentSpeed:{0}", CurrSpeed); } } }
客戶端調(diào)用:
static void Main(string[] args) { EventCar bmw = new EventCar("Henllyee", 110); bmw.AbortToBlow += new EventCar.CarEventHandler(CarAboutToBlow); bmw.Exploded += new EventCar.CarEventHandler(CarExploede); for (var i = 0; i < 10; i++) { bmw.Accelerate(20); Console.ReadLine(); } } public static void CarAboutToBlow(string msg) { Console.WriteLine(msg); } public static void CarExploede(string msg) { Console.WriteLine(msg); }
運(yùn)行效果:
規(guī)范的事件與匿名方法
我們看我們定義的事件似乎跟底層的事件有點(diǎn)不一樣,底層的委托的第一個(gè)參數(shù)一般為System.Object類型的,第二個(gè)參數(shù)一般為派生自System.EventArgs類型的。第一個(gè)參數(shù)一般表示發(fā)送事件的對(duì)象,第二個(gè)參數(shù)表示與該事件相關(guān)的參數(shù)。我們可以定義個(gè)CarEventArgs:
public class CarEventArgs : EventArgs { public readonly string msg; public CarEventArgs(string Msg) { msg = Msg; } }
委托就可以修改成:
public delegate void CarEventHandler(object send, CarEventArgs e);
使用時(shí):
if (IsDead) { if (this.Exploded!= null) Exploded(this,new CarEventArgs("The Car Is Dead")); }
在上面的時(shí)候我們當(dāng)監(jiān)聽事件的時(shí)候都是通過定義一個(gè)唯一的與委托簽名匹配的方法,在有的時(shí)候我們監(jiān)聽的方法也許只需要處理一段簡單的邏輯,所以每次都定義個(gè)方法畢竟比較麻煩。大都時(shí)候我們可以通過匿名方法來監(jiān)聽事件,如:
bmw.AbortToBlow += delegate(object sender, CarEventArgs e) { Console.WriteLine("Message:{0}",e.msg); };
總結(jié)
這篇中分析了下事件跟委托的關(guān)系,其實(shí)事件只是語法定義上的方便,關(guān)鍵還是理解了委托就行。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:博客園