part01.04 事件
1. C#事件的概念
C# 中時間允許一個對象將發(fā)生的事件通知其他對象,將發(fā)生的事件的事件源叫發(fā)行者,通知其他的對象叫訂閱者,但是訂閱者可以定義也可以不定義(事件發(fā)生者也可以是事件的訂閱者)
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 var user = new User(); 6 user.Name = "xiaohon"; 7 user.Password = "123"; 8 9 user.EventLogin += new User.DelegateLogin(User_EventLogin); 10 user.Login(); 11 12 } 13 14 private static void User_EventLogin() 15 { 16 Console.WriteLine("login seccessful"); 17 } 18 } 19 20 class User 21 { 22 public delegate void DelegateLogin(); // 定義一個委托 23 public event DelegateLogin EventLogin; // 定義一個事件(事件用關(guān)鍵字加委托名來定的且后面無括號) 24 25 public string Name { get; set; } 26 public string Password { get; set; } 27 28 /// <summary> 29 /// 類的方法(可做為方法的參數(shù)即委托) 30 /// </summary> 31 public void Login() 32 { 33 Console.WriteLine("Login....."); 34 35 // 引發(fā)事件 36 if (EventLogin != null) 37 { 38 EventLogin(); 39 } 40 } 41 } View Code2. 事件的聲明
。事件是成員,它必須聲明在類或類型中,和其他成員一樣。
。由于事件不是類型,我們不能像委托那樣使用對象創(chuàng)建表達(dá)式(new 表達(dá)式)來創(chuàng)建它的對象。
。事件成員被隱式自動初始化為 null 。
3. 委托類型和 EventHandler
。事件聲明需要委托類型的名字,我們可以聲明一個委托類型或使用已存在的。聲明一個委托類型,它必須指定事件保存的方法的簽名和返回類型。
。更好的方案就是使用 EventHandler 委托。
4. 觸發(fā)事件
。在觸發(fā)事件之前和 null 進(jìn)行比較,從而查看是否包含任何事件處理程序,如果事件是 null ,則表示沒有。
。出發(fā)事件本身看起來像調(diào)用函數(shù)一樣。
5. 訂閱事件
。使用 += 運(yùn)算符來添加事件處理程序(即綁定多個方法),方法可以是:
。實例方法
。靜態(tài)方法
。匿名方法
。Lambda 表達(dá)式
。使用 -= 運(yùn)算符來移除事件處理程序(即刪除多個方法)
6. 關(guān)于 EventArg 類
?。EventArgs 被設(shè)計為不能專遞任何數(shù)據(jù)。它用于不需要傳遞數(shù)據(jù)的事件處理程序。
。通過擴(kuò)展 EventArgs 來傳遞數(shù)據(jù)。
7. 觀察者(Observer)設(shè)計模式的一種實現(xiàn)
熱水器,加電燒水,當(dāng)水溫超過 95 度的時候:
1. 揚(yáng)聲器會開始 發(fā)出語音,告訴你水的溫度;
2. 液晶屏也會改變水溫的顯示,來提示水已經(jīng)快燒開了。
如何在水快燒開的時候通知報警器和顯示器?
?
1. 警報器和顯示器告訴熱水器,它對它的溫度比較感興趣(注冊)。
2. 熱水器知道后保留對警報器和顯示器的引用。
3. 熱水器進(jìn)行燒水這一動作,當(dāng)水溫超過 95 度時,通過對警報器和顯示器的引用,自動 調(diào)用警報器的 MakeAlert()方法、顯示器的 ShowMsg()方法
。Observer 設(shè)計模式:Observer 設(shè)計 模式是為了定義對象間的一種一對多的依賴關(guān)系,以便于當(dāng)一個對象的狀態(tài)改變時,其他依賴 于它的對象會被自動告知并更新。Observer 模式是一種松耦合的設(shè)計模式
。Observer 設(shè)計模式中主要包括如下兩類對象:
。Subject:監(jiān)視對象,它往往包含著其他對象所感興趣的內(nèi)容。在本范例中,熱水器就是一個監(jiān)視對象,它包含的其他對象所感興趣的內(nèi)容,就是 temperature 屬性,當(dāng)這個屬性的值快到 100 時,會不斷把數(shù)據(jù)發(fā)給監(jiān)視它的對象。
。Observer:觀察者,它監(jiān)視 Subject,當(dāng) Subject 中的某件事發(fā)生的時候,會告知 Observer,而 Observer 則會采取相應(yīng)的行動。在本范例中,Observer 有警報器和顯示器,它們采取的行動分別是發(fā)出警報和顯示水溫。
常規(guī)的實現(xiàn):
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 var heater = new Heater(); // 創(chuàng)建熱水器對象 6 var alarm = new Alarm(); // 創(chuàng)建報警器對象 7 8 heater.BoilEvent += alarm.MakeAlarm; // 注冊報警方法 9 heater.BoilEvent += (new Alarm()).MakeAlarm; // 給匿名對象注冊方法 10 heater.BoilEvent += Display.ShowMsg; // 注冊靜態(tài)方法 11 12 heater.BoilWater(); // 開始燒水,根據(jù)方法的條件會自動調(diào)用注冊的方法 13 14 Console.ReadKey(); 15 } 16 } 17 18 /// <summary> 19 /// 熱水器 20 /// </summary> 21 class Heater 22 { 23 private int temperature; // 溫度 24 public delegate void BoilHandler(int temp); // 聲明委托 25 public event BoilHandler BoilEvent; // 聲明事件 26 27 /// <summary> 28 /// 燒水 29 /// </summary> 30 public void BoilWater() 31 { 32 for(int i = 95; i <= 100; i++) 33 { 34 temperature = i; 35 if (temperature > 95) 36 { 37 // 如果定義的事件有對象注冊 38 if(BoilEvent != null) 39 { 40 // 則執(zhí)行其中的所有方法 41 BoilEvent(temperature); 42 } 43 } 44 } 45 } 46 } 47 48 /// <summary> 49 /// 溫度顯示器 50 /// </summary> 51 class Display 52 { 53 /// <summary> 54 /// 顯示方法 55 /// </summary> 56 /// <param name="temp">溫度</param> 57 public static void ShowMsg(int temp) 58 { 59 Console.WriteLine("顯示器:水快燒開了,當(dāng)前溫度是{0}度", temp); 60 } 61 } 62 63 /// <summary> 64 /// 報警器 65 /// </summary> 66 class Alarm 67 { 68 /// <summary> 69 /// 報警方式 70 /// </summary> 71 /// <param name="temp">溫度</param> 72 public void MakeAlarm(int temp) 73 { 74 Console.WriteLine("當(dāng)前溫度是" + temp + "度"); 75 } 76 } 常規(guī)的實現(xiàn)8. .Net Framework 中的委托和事件
1. 委托類型的名稱都應(yīng)該以 EventHandler 結(jié)束。
2. 委托的原型定義:有一個 void 返回值,并接受兩個輸入?yún)?shù):一個 Object 類型,一個 EventArgs 類型(或繼承自 EventArgs)。
3. 事件的命名為委托去掉 EventHandler 之后剩余的部分。
4. 繼承自 EventArgs 的類型應(yīng)該以 EventArgs 結(jié)尾。
5. 委托聲明原型中的 Object 類型的參數(shù)代表了 Subject ,也就是監(jiān)視對象,在本例中是 Heater(熱水器)。回調(diào)函數(shù)(比如 Alarm 的MakeAlert)可以通過它訪問觸發(fā)事件的對象(Heater)。
6. EventArgs 對象包含了 Observer 所感興趣的數(shù)據(jù),在本例中是 temperature。
改進(jìn)后的代碼:
?
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 var heater = new Heater(); // 創(chuàng)建熱水器對象 6 var alarm = new Alarm(); // 創(chuàng)建報警器對象 7 8 //heater.BoilEvent += alarm.MakeAlarm; // 注冊報警方法 9 //heater.BoilEvent += (new Alarm()).MakeAlarm; // 給匿名對象注冊方法 10 11 heater.Boiled += Display.ShowMsg; // 注冊靜態(tài)方法 12 heater.Boiled += new Heater.BoilEventHandler(alarm.MakeAlarm); // 另一種注冊方式 13 14 heater.BoilWater(); // 開始燒水,根據(jù)方法的條件會自動調(diào)用注冊的方法 15 16 Console.ReadKey(); 17 } 18 } 19 20 /// <summary> 21 /// 熱水器 22 /// </summary> 23 class Heater 24 { 25 private int _Temperature; // 溫度 26 public string Brand = "格星 X-1219"; 27 public string Manufacturer = "xx 格星電器有限責(zé)任公司"; 28 29 // 委托的原型定義:有一個 void 返回值,并接受兩個輸入?yún)?shù):一個 Object 類型, 一個 EventArgs 類型(或繼承自 EventArgs) 30 public delegate void BoilEventHandler(object sender,BoiledEventArgs e); // 聲明委托 委托類型的名稱都應(yīng)該以 EventHandler 結(jié)束 31 public event BoilEventHandler Boiled; // 聲明事件 事件的命名為委托去掉 EventHandler 之后剩余的部分 32 33 /// <summary> 34 /// 構(gòu)建一個可以重寫的方法,以便它的派生類拒絕其他對象的訪問 35 /// </summary> 36 /// <param name="e">事件參數(shù)</param> 37 protected virtual void OnBoiled(BoiledEventArgs e) 38 { 39 if(Boiled != null) 40 { 41 Boiled(this, e); 42 } 43 } 44 45 /// <summary> 46 /// 燒水 47 /// </summary> 48 public void BoilWater() 49 { 50 for(int i = 95; i <= 100; i++) 51 { 52 _Temperature = i; 53 if (_Temperature > 95) 54 { 55 BoiledEventArgs e = new BoiledEventArgs(_Temperature); 56 OnBoiled(e); 57 } 58 } 59 } 60 } 61 62 /// <summary> 63 /// 定義一個事件參數(shù)類,用于承載需要傳遞給 Observer 所感興趣的信息 64 /// 繼承自 EventArgs 的類型應(yīng)該以 EventArgs 結(jié)尾 65 /// EventArgs 對象包含了 Observer 所感興趣的數(shù)據(jù),在本例中是 _Temperature 66 /// </summary> 67 public class BoiledEventArgs : EventArgs 68 { 69 public readonly int _Temperature; 70 71 public BoiledEventArgs(int temp) 72 { 73 this._Temperature = temp; 74 } 75 } 76 77 /// <summary> 78 /// 溫度顯示器 79 /// </summary> 80 class Display 81 { 82 /// <summary> 83 /// 顯示方法 84 /// </summary> 85 /// <param name="temp">溫度</param> 86 public static void ShowMsg(object sender,BoiledEventArgs e) 87 { 88 var obj = sender as Heater; 89 Console.WriteLine("顯示器{0}({1})", obj.Brand, obj.Manufacturer); 90 Console.WriteLine("顯示器:水快燒開了,當(dāng)前溫度是{0}度", e._Temperature); 91 } 92 } 93 94 /// <summary> 95 /// 報警器 96 /// </summary> 97 class Alarm 98 { 99 /// <summary> 100 /// 報警方式 101 /// </summary> 102 /// <param name="temp">溫度</param> 103 public void MakeAlarm(object sender,BoiledEventArgs e) 104 { 105 Console.WriteLine("當(dāng)前溫度是" + e._Temperature + "度"); 106 } 107 } 改進(jìn)后的代碼?
?
?
?
參考網(wǎng)址:https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/events/
?
轉(zhuǎn)載于:https://www.cnblogs.com/huangzewei/p/7300080.html
總結(jié)
以上是生活随笔為你收集整理的part01.04 事件的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 36日期计算包含计算某月某日是星期几的公
- 下一篇: HDU 5781 ATM Mechine