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