本次是對第一篇事件隨筆的補充筆記,涉及題目依然使用上一篇的習題。上一篇地址:https://www.cnblogs.com/FavoriteMango/p/11685702.html
1.事件的定義
事件的定位可以參考屬性,C#中,屬性是對字段的封裝,相對而言,基於委托來聲明的事件也是對委托的封裝,但是屬性≠字段,同樣事件≠委托。至於為何封裝,可另行查閱文檔。
2.事件的簡要聲明和詳細聲明
通常的學習案例中大部分對事件的使用都是通過簡要聲明(語法糖)的方式使用的,包括上一篇隨筆中我初學事件時的例子,但這次有接觸到事件聲明的詳細流程。
事件的簡要聲明中省略了對委托字段的聲明步驟,由於Action和Fun這兩個委托類,你甚至可以完全不聲明委托類型,並且由於語法糖,你可能會把委托和事件完全混淆,這是錯誤的。
事件的詳細聲明需要有對委托類型的定義,事件參數的定義,委托字段的定義,還有事件本身的定義,對事件的定義中還有add和remove關鍵字以及相關邏輯的處理(add和remove可以用屬性的get、set的定義來參考),強烈建議通過詳細的聲明流程來理解事件。
3.定義事件時需要的一些參數
雖然沒有硬性規定事件必須要有哪些參數,但所有事件基於情理最好有兩個參數,第一個是事件的發起者,第二個是事件所包含的相關信息。參考Winform,所有的事件都有sender和e兩個參數,他們分別對應發起者和信息。
在這里C#將sender定義為Object,也給出了基本的信息類(EventArgs類),而自定義的信息類都要繼承EventArgs類,並且在定義類的時候類名都要加EventArgs為后綴(例如后面的AnimalEventArgs),這是一種命名規范。
4.其他一些要注意的地方
聲明委托類型時,要注意同為數據類型的委托是和類(class)平級的存在,它應當(但不絕對)聲明在和類平級的命名空間里。
簡要聲明是一種語法糖,它簡化了了事件的使用流程,但是也容易混淆概念,在下面的代碼中請重點注意在事件的發起者中對於事件的定義和事件的觸發兩處的代碼。
5.習題部分
回到習題,依然是開槍的事件,首先是事件的相關參數的定義,包括委托類型的定義,事件信息類的定義:
//聲明委托類型 //Parson : 事件發起者的類 public delegate void FireEventHandler(Parson parson, FireEventArgs e); /// <summary> /// 事件參數中的信息類 /// </summary> public class FireEventArgs : EventArgs { public Animal Animal { get; set; } }
然后是事件的發起者和訂閱者
/// <summary> /// 事件的發起者 /// </summary> public class Parson { //委托類型的字段 private FireEventHandler fireEventHandler; //封裝委托類型的事件 public event FireEventHandler Fire { add { //添加事件處理器 //value:在訂閱事件時添加的事件處理器 this.fireEventHandler += value; } remove { //移除事件處理器 this.fireEventHandler -= value; } } public string Name { get; set; } public void OnFire(FireEventArgs e) { Console.WriteLine("{0}正在開槍。", Name); if (fireEventHandler != null) { //觸發事件 fireEventHandler.Invoke(this, e); } } } /// <summary> /// 事件的訂閱者 /// </summary> public class Animal { public string Name { get; set; } internal void Action(Parson sender, FireEventArgs e) { Console.WriteLine("由於" + sender.Name + "開槍," + e.Animal.Name + "受到了驚嚇。"); if (e.Animal.Name == "鳥") { Console.WriteLine(e.Animal.Name + "飛了"); } } }
最后是訂閱事件
class Program { static void Main(string[] args) { //人開槍,鳥飛了 //事件擁有者:人 //事件本身:開槍 //事件響應者:鳥 //事件處理:飛了 //訂閱關系:鳥 → 開槍 //事件的完整聲明 Parson parson = new Parson { Name = "Your name" }; Animal animal = new Animal { Name = "Animal name" }; parson.Fire += animal.Action; parson.OnFire(new FireEventArgs { Animal = animal }); } }
把Animal的name屬性賦值為“鳥”
class Program { static void Main(string[] args) { //人開槍,鳥飛了 //事件擁有者:人 //事件本身:開槍 //事件響應者:鳥 //事件處理:飛了 //訂閱關系:鳥 → 開槍 //事件的完整聲明 Parson parson = new Parson { Name = "Your Name" }; Anime anime = new Anime { Name = "鳥" }; parson.Fire += anime.Action; parson.OnFire(new FireEventArgs { Anime = anime }); } }
運行可得結果: