[.NET] C# 学问回顾

[.NET] C# 知识回顾

C# 知识回顾 - Event 事件

【博主】反骨仔    【原文】http://www.cnblogs.com/liqingwen/p/6060297.html  

  昨天,通过《C# 知识回顾 - 事件入门》介绍了事件的定义及简单用法,今天我们通过控制台来看下“发布 - 订阅”的基本用法。

 

目录

 

一、发布符合 .NET 准则的事件

  下面的过程演示了如何将符合标准 .NET 模式的事件添加到您的类和结构中。.NET类库中的所有事件均基于 EventHandler 委托,定义如下:  

public delegate void EventHandler(object sender, EventArgs e);

  你可以尝试手动输入 EventHandler ,然后按下“F12”跳转到定义:

[.NET] C# 学问回顾

 

  .NET Framework 2.0 引入了此委托的一个泛型版本,即 EventHandler<TEventArgs>

  【备注】虽然您定义的类中的事件可基于任何有效委托类型(甚至是可返回值的委托),但是,通常建议您使用 EventHandler 让事件基于 .NET 模式,如下面的示例所示。

 

二、采用 EventHandler 模式发布事件

  1.(如果不需要与事件一起发送自定义数据,请跳过此步骤,进入步骤 3a。)在发行者类和订阅方类均可看见的范围中声明自定义数据的类。然后添加保留您的自定义事件数据所需的成员。

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.(如果您使用的是 EventHandler<TEventArgs> 的泛型版本,请跳过此步骤。)在发布类中声明一个委托。  为它指定以 EventHandler 结尾的名称。  第二个参数指定自定义 EventArgs 类型。 

    delegate void MyEventHandler(object sender, MyEventArgs args);

 

  3.使用以下任一步骤,在发布类中声明事件。

    (1)如果没有自定义 EventArgs 类,事件类型就是非泛型 EventHandler 委托。无需声明委托,因为它已在创建 C# 项目时包含的 System 命名空间中进行了声明。将以下代码添加到发行者类中。 

public event EventHandler MyEvent;

 

    (2)如果使用的是 EventHandler 的非泛型版本,并且您有一个由 EventArgs 派生的自定义类,请在发布类中声明您的事件,并且将来自步骤 2 的委托用作类型。

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     }

 [.NET] C# 学问回顾

 

四、实现自定义事件访问器

  事件是特殊类型的多路广播委托,只能从声明它的类中调用。客户端代码通过提供对应在引发事件时调用的方法的引用来订阅事件。这些方法通过事件访问器添加到委托的调用列表中,事件访问器类似于属性访问器,不同之处在于事件访问器被命名为 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 (续)

  《C# 知识回顾 - 事件入门

 


【参考】微软官方文档

1楼反骨仔(二五仔)
有没搞错,被移除首页