C# 知识回顾 - Event 事件
【博主】反骨仔 【原文】http://www.cnblogs.com/liqingwen/p/6060297.html
序
昨天,通过《C# 知识回顾 - 事件入门》介绍了事件的定义及简单用法,今天我们通过控制台来看下“发布 - 订阅”的基本用法。
目录
- 发布基于 .NET 类库的事件
- 采用 EventHandler 模式发布事件
- 一个简单的发布订阅 Demo
- 实现自定义事件访问器
一、发布基于 .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# 知识回顾 - 序列化》
《C# 知识回顾 - 表达式树 Expression Trees》
《C# 知识回顾 - 特性 Attribute》、《剖析 AssemblyInfo.cs - 了解常用的特性 Attribute》
《C# 知识回顾 - 委托 delegate》、《C# 知识回顾 - 委托 delegate (续)》
《C# 知识回顾 - 事件入门》
【参考】https://msdn.microsoft.com/zh-cn/library/w369ty8x(v=vs.80).aspx
【参考】微软官方文档