C# 事件(第四章)
委托確實(shí)是一個(gè)有趣的結(jié)構(gòu),它允許內(nèi)存中的對(duì)象進(jìn)行雙向?qū)υ挕H欢?#xff0c;你可能會(huì)同意,從頭使用委托會(huì)有一些重復(fù)代碼(定義托委,聲明必要的成員變量,以及創(chuàng)建自定義的注冊(cè)/注銷方法來(lái)保護(hù)封裝等)。
除了時(shí)間之外,這樣使用委托來(lái)作為應(yīng)用程序的回調(diào)機(jī)制會(huì)有另一個(gè)問(wèn)題是:如果我們沒(méi)有反委托成員變量定義為私有的,調(diào)用者就可以直接訪問(wèn)委托對(duì)象。這樣,調(diào)用者就可以把變量賦值為新的委托對(duì)象(實(shí)際上也就刪除了當(dāng)前要調(diào)用的方法列表),更糟糕的是,調(diào)用者可以直接調(diào)用委托的調(diào)用列表。為說(shuō)明這個(gè)問(wèn)題請(qǐng)看如下代碼:
?
public class Car { //一個(gè)委托public delegate void Exploded(string msg);//公共的,沒(méi)有輔助方法public Exploded explodedList;//觸發(fā)分解的通知public void Accelerate(int delta){if(explodedList!=null)explodedList("Sorry,this car is dead..");} }我們不再有使用自定義的注冊(cè)方法封裝的私有委托成員變量。因?yàn)檫@些成員確實(shí)是公共的,調(diào)用者可以直接訪問(wèn)explodedList成員,把這個(gè)類型重新分配給新的Exploded對(duì)象并且隨時(shí)調(diào)用委托:
class Program {static void Main(string[] args){Console.WriteLine("Agh No Encapsulation!");//創(chuàng)建一個(gè)CarCar myCar=new Car();//我們可以直接訪問(wèn)委托myCar.explodedList=new Car.Exploded(CallWhenExploded);myCar.acclerate(10);//現(xiàn)在可以賦值一個(gè)全新對(duì)象myCar.explodedList=new Car.Exploded(CallHereToo);myCar.acclerate(10);//調(diào)用者還可以直接調(diào)用委托myCar.explodedList.Invoke("hee,hee,hee");}static void CallWhenExploded(string msg){Console.WrtieLine(msg);}static void CallHereToo(string msg){Console.WrtieLine(msg);} }? 公共委托成員打破了封裝,不僅會(huì)導(dǎo)致代碼難以維護(hù)和調(diào)試,還會(huì)導(dǎo)致應(yīng)用程序安全風(fēng)險(xiǎn)!顯然,我們不希望給其它應(yīng)用程序必變委托指向的權(quán)力以及沒(méi)有我們的許可直接調(diào)用成員的權(quán)力。
enent關(guān)鍵字
為了簡(jiǎn)化自定義方法的構(gòu)建來(lái)為委托調(diào)用列表增加和刪除方法,C#提供了event關(guān)鍵字。在編譯器處理event關(guān)鍵字的時(shí)候,它會(huì)自動(dòng)提供注冊(cè)和注銷的方法以及委托類型任何必要的成員變理。這些委托成員變量總是聲明為私有的,因此不能直接從觸發(fā)事件的對(duì)象訪問(wèn)它們。可以肯定的是,event關(guān)鍵字就像一塊語(yǔ)法糖,只是節(jié)省了我們打字的時(shí)間。
定義一個(gè)事件分為兩個(gè)步驟。首先,我們需要定義一個(gè)委托,它包含在事件觸發(fā)時(shí)將要調(diào)用的方法。其次,通過(guò)C# event關(guān)鍵字用相關(guān)委托聲明這個(gè)事件。
Car類型事件會(huì)取與前面的調(diào)用者(AboutToBelow和Exploded)同樣的名字。事件相關(guān)聯(lián)的調(diào)用者會(huì)被命名為CarEventHandler。下面是對(duì)Car類型的第一次修改:?
public calss Car {//這個(gè)委托用來(lái)與Car的事件協(xié)作public delegate void CarEventHandler(string msg);//定義每個(gè)委托類型的成員變量public event CarEventHandler Exploded;public event CarEventHandler AboutToBlow;... }向調(diào)用者發(fā)送一個(gè)事件,就如通過(guò)名稱和相關(guān)聯(lián)委托定義的必需參數(shù)來(lái)指定事件這么簡(jiǎn)單。為確保調(diào)用者注冊(cè)事件,需要在調(diào)用委托的方法之前檢查這個(gè)事件是否是無(wú)效值。了解這些后,下面來(lái)看修改后的Car的Accelerate()方法:
public void Accelerate(int delta) {//如果汽車不能用了,觸發(fā)引爆事件if(carIsDead){if(Exploded!=null){Exploded("sorry,this card is dead...");}}else{currSpeed+=delta;//已經(jīng)不能用了嗎?if(10==maxSpeed-currSpeed&&AboutToBlow!-null_{AboutToBlow("Careful boddy! Gonna blow!");}//還好著呢if(currSpeed>=maxSpeed)carIsDead=true;elseConsole.WriteLine("CurrSpeed={0}",currSpeed);} }這樣,我們已經(jīng)設(shè)定了Car對(duì)象發(fā)送自定事件,這不再需要定義自定義注冊(cè)函數(shù),也不需要聲明托委成員變量。
臨聽(tīng)傳入的事件
C#事件也簡(jiǎn)化了注冊(cè)調(diào)用者事件處理程序的操作。現(xiàn)在調(diào)用者僅需使用+= 和-=運(yùn)算符即可。
class Program {static void main(string[] args){Console.Write("####Delegates as events ####\n");Car cl=new Car("SlugBug",100,10);//注冊(cè)事件處理程序cl.OnAboutToBlow +=new Car.CarEventHandler(CarIsAlmostDoomed);cl.OnAboutToBlow +=new Car.CarEventHandler(CarAboutToBlow);cl.CarEventHandler d=new Car.CarEventHandler(CarExploded);c1.Exploded +=d;Console.WriteLine("Speed up");for(int i=0;i<7;i++)cl.Accelerate(20);//從調(diào)用列表中移除CarExploded方法c1.Exploded -=d;Console.WriteLine("Speed up");for(int i=0;i<7;i++)cl.Accelerate(20);Console.ReadLine();}public static void CarAboutToBlow(string msg){ Console.WriteLine(msg);}public static void CarIsAlmostDoomed(string msg){ Console.WriteLine(msg);}public static void CarExploded(stirng msg){ Console.WriteLine(msg);} }?
轉(zhuǎn)載于:https://www.cnblogs.com/longProgrammer/p/3192202.html
總結(jié)
以上是生活随笔為你收集整理的C# 事件(第四章)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 多项式相乘与相加演示
- 下一篇: Matlab生成动态链接库供C#调用