C# 知識回顧 - Event 事件
【博主】反骨仔 【原文】http://www.cnblogs.com/liqingwen/p/6060297.html
序
昨天,通過《C# 知識回顧 - 事件入門》介紹了事件的定義及簡單用法,今天我們通過控制台來看下“發布 - 訂閱”的基本用法。
目錄
一、發布基於 .NET 類庫的事件
.NET類庫中的所有事件均基於 EventHandler 委托,定義如下:
public delegate void EventHandler(object sender, EventArgs e);
你可以嘗試手動輸入 EventHandler ,然后按下“F12”跳轉到定義:

.NET 2.0 引入了該委托的一個泛型版本,即 EventHandler<TEventArgs>。
【備注】雖然我們定義的事件可以基於任何自定的委托類型,但建議使用內置的 EventHandler 進行擴展。
二、采用 EventHandler 模式發布事件
1.這里選擇繼承了 BCL 中的類 EventArgs,可以在事件的觸發時進行數據的傳遞。
1 class MyEventArgs : EventArgs 2 { 3 public string Message { get; private set; } 4 5 public MyEventArgs(string message) 6 { 7 Message = message; 8 } 9 }
2.這里的第二個參數就是自定義的 MyEventArgs 類型,它繼承了 EventArgs。
delegate void MyEventHandler(object sender, MyEventArgs args);
3.聲明事件的幾種形式:
(1)如果沒有自定義 EventArgs 類,你可以直接使用 C# 中默認提供的非泛型 EventHandler 委托。
public event EventHandler MyEvent;
(2)如果使用的是非泛型的 EventHandler,並且寫了一個自定義由 EventArgs 派生的類,可修改如下。
public event MyEventHandler MyEvent;
(3)如果使用的是高級的泛型版本,就不需要自定義委托。你只需要簡單地將事件類型指定為 EventHandler<MyEventArgs>,將尖括號中的內容替換為自己的類的名稱。
public event EventHandler<MyEventArgs> MyEvent;
三、一個簡單的發布訂閱 Demo
下面的示例通過將自定義的 MyEventArgs 類和 EventHandler<TEventArgs> 進行演示:
This is MyEventArgs.cs //事件參數
1 /// <summary> 2 /// 事件參數 3 /// </summary> 4 /// <remarks>一個自定義的類:自定義事件的參數</remarks> 5 class MyEventArgs : EventArgs 6 { 7 public string Message { get; } 8 9 public MyEventArgs(string message) 10 { 11 Message = message; 12 } 13 }
This is Publisher.cs //發布者
1 /// <summary> 2 /// 事件發布者 3 /// </summary> 4 class Publisher 5 { 6 //聲明一個泛型事件 7 public event EventHandler<MyEventArgs> MyEvent; 8 9 public void Publish() 10 { 11 Console.WriteLine("Publis is starting"); 12 13 //你可以在事件觸發前寫些代碼 14 15 OnMyEvent(new MyEventArgs(DateTime.Now.ToString())); 16 } 17 18 /// <summary> 19 /// 觸發事件 20 /// </summary> 21 /// <param name="args"></param> 22 /// <remarks>虛方法,允許子類重寫調用行為</remarks> 23 protected virtual void OnMyEvent(MyEventArgs args) 24 { 25 //只有在事件訂閱時(!= null),才觸發事件 26 MyEvent?.Invoke(this, args); 27 } 28 }
This is Subscriber.cs //訂閱者
1 /// <summary> 2 /// 訂閱者 3 /// </summary> 4 class Subscriber 5 { 6 public Guid Guid { get; } 7 8 public Subscriber(Publisher publisher) 9 { 10 Guid = Guid.NewGuid(); 11 //使用 C# 2 的語法進行訂閱 12 publisher.MyEvent += Publisher_MyEvent; 13 } 14 15 /// <summary> 16 /// 事件處理程序 17 /// </summary> 18 /// <param name="sender"></param> 19 /// <param name="args"></param> 20 private void Publisher_MyEvent(object sender, MyEventArgs args) 21 { 22 Console.WriteLine($" Message is {args.Message}, Guid is {Guid}."); 23 } 24 }
This is Program.cs //控制台,用於啟動
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 var publisher = new Publisher(); 6 var subscriber1 = new Subscriber(publisher); 7 var subscriber2 = new Subscriber(publisher); 8 9 //觸發事件 10 publisher.Publish(); 11 12 Console.WriteLine("OK!"); 13 Console.Read(); 14 } 15 }

四、實現自定義事件訪問器
事件一種是特殊類型的多播委托,只能從聲明它的類中進行調用。這些方法需要預先通過事件訪問器添加到委托的調用列表中,事件訪問器跟我們平時使用的屬性訪問器,特殊的是他們的名字,事件訪問器被命名為 add 和 remove。如果在代碼中沒有提供自定義的事件訪問器,編譯器會自動添加事件訪問器。但在某些情況下,您可能需要提供自定義的行為。
1 class MyClass 2 { 3 /// <summary> 4 /// 鎖 5 /// </summary> 6 private static object Locker = new object(); 7 8 /// <summary> 9 /// 接口 10 /// </summary> 11 public interface IMyEvent 12 { 13 event EventHandler OnCall; 14 } 15 16 public class MyEvent : IMyEvent 17 { 18 /// <summary> 19 /// 觸發前事件 20 /// </summary> 21 event EventHandler PreEvent; 22 23 public event EventHandler OnCall 24 { 25 add 26 { 27 lock (Locker) 28 { 29 PreEvent += value; 30 } 31 } 32 remove 33 { 34 lock (Locker) 35 { 36 PreEvent += value; 37 } 38 } 39 } 40 } 41 }
傳送門
《C# 知識回顧 - 委托 delegate》、《C# 知識回顧 - 委托 delegate (續)》
【參考】https://msdn.microsoft.com/zh-cn/library/w369ty8x(v=vs.80).aspx
【參考】微軟官方文檔
