• [.NET] C# 知识回顾


    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 (续)

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


    【参考】https://msdn.microsoft.com/zh-cn/library/w369ty8x(v=vs.80).aspx

    【参考】微软官方文档

  • 相关阅读:
    python之路_爬虫之selenium模块
    python之路_爬虫之requests模块补充
    扩展中国剩余定理讲解
    扩展中国剩余定理讲解
    bzoj3225 [Sdoi2008]立方体覆盖——扫描线
    差分约束讲解
    CF917C Pollywog —— 状压DP + 矩乘优化
    斜率优化讲解
    AC自动机讲解
    BZOJ2870—最长道路tree
  • 原文地址:https://www.cnblogs.com/liqingwen/p/6060297.html
Copyright © 2020-2023  润新知