C#事件(包含完整声明和简易声明)

  1. 事件基于委托,需要用委托进行约束
    1. 约束了事件能向响应者(订阅者)发送的信息
    2. 约束了事件响应者(订阅者)能收到的消息
    3. 事件处理器需要同时满足上述2个要求才能订阅该事件
    4. 只有委托实例能够通过记录和引用方法,来保存事件处理器
  2. 事件的本质是委托字段的一个包装器
    • 这个包装器对委托字段的访问起到限制作用,让程序更加安全
    • 事件对外界隐藏了委托实例的大部分功能,只暴露了添加和移除事件处理器的功能
    • 事件的右边只能用+=或者-=操作符
  3. 事件是一个成员,只能写在类里
  4. 事件的作用是让对象或者类具备通知能力
  5. 事件模型的5个组成要素
    • 事件拥有者(发布者)
    • 事件成员
    • 事件的响应者(订阅者)
    • 事件处理器——本质是一个回调方法
    • 事件订阅
  6. 事件的完整声明
    1. 首先,创建事件的拥有者(发布者)
      public class MessageEvent
          {
          }
    2. 创建事件成员

      创建事件成员之前,需要创建一个委托来约束他,这类委托的命名通常为xxx+EventHandler,代表该委托是专门为事件服务的,委托一般包含两个参数(由Win32API演化而来),第一个参数是事件的拥有者(发布者),第二个参数为事件发生后要向响应者(订阅者)传送的事件消息数据,下面创建这个类

      //创建EventArgs的派生类,包含需要传送给事件的信息
          public class MessageEventArgs : EventArgs
          {
              public string name { get; set; }
              public string message { get; set; }
          }

      在创建该类时,通常会继承EventArgs类,为了统一规范,也是标准惯例,命名通常为xxx+EventArgs,如果这里没有需要传送的数据,可以将委托的第二个参数填为EventArgs类,该类用于不需要传递数据的事件处理器

      public delegate void SendMessageEventHandler(MessageEvent messageEvent, EventArgs e);

      下面可以开始创建事件成员了

      //创建委托
          public delegate void SendMessageEventHandler(MessageEvent messageEvent, MessageEventArgs e);
      public class MessageEvent
          {
              private  SendMessageEventHandler sendMessageEventHandler;
              //声明事件,用委托类型来约束事件参数
              public  event SendMessageEventHandler SendMessage
              {
                  add//添加器
                  {
                      sendMessageEventHandler += value;
                      //这里写的代码会在订阅事件的时候同时执行
      
                  }
                  remove//移除器
                  {
                      sendMessageEventHandler -= value;
                      //这里写的代码会在移除事件的时候同时执行
                  }
              }
          }

      首先根据上面创建的委托类型创建一个字段,这个字段就是用来存储、引用事件处理器的, 这个字段不需要被外界访问,所以访问级别为private。事件成员的访问级别为public,创建事件成员时需要加上关键字event,同时用相应的委托类型来约束事件。

      事件后面跟着一个语句块,用来写事件的添加器和移除器,添加器和移除器重的value代表从外面传进来的事件处理器,同时,在添加器和移除器中写的代码会在事件订阅时一起生效。

      事件的命名应该为带有时态的动词或者动词短语,代表正在做xxx事情或者做完了xxx事情

    3. 创建事件的响应者(订阅者)

      public class MessageEventAction
          {
          }
      

      然后在事件的响应者(订阅者)中添加事件处理器

      //SendMessage事件的处理器
              public  void Action(MessageEvent messageEvent, MessageEventArgs e)
              {
      
                  
                  MessageBox.Show($"name:{e.name},message:{e.message}");//这个方法是让wpf出现弹窗,在弹窗中显示内容
                      
              }
    4. 将触发事件的方法写在事件拥有者中

       //事件拥有者内部方法触发事件
              protected  void OnEventAction(string name, string message)
              {
      
      
                  
                  if (sendMessageEventHandler != null)//没有地方订阅事件时,不触发
                  {
                      MessageEventArgs e = new MessageEventArgs();
                      e.name = name;
                      e.message = message;
      
                      sendMessageEventHandler.Invoke(null, e);
                  }

      通常,触发事件的方法命名为Onxxx,访问级别应为Protected,不能让外界进行访问,事件的触发只能由事件的拥有者(发布者)来做

    5. 最后进行事件的订阅

      class program
      {
          static void Main(string[] args)
          {
              MessageEvent messageEvent = new MessageEvent();
              MessageEventAction messageEventAction = new MessageEventAction();
              messageEvent.SendMessage += messageEventAction.Action;
              string name = "hello";
              string message = $"world";
              messageEvent.EventAction(name, message);
          }
      }

      这样,一个完整的事件声明就完成了,他包含了事件的拥有者(发布者)、事件成员、事件的响应者(订阅者)、事件处理器以及事件的订阅

  7. 事件的简易声明

    1. 事件的简易声明是一个语法糖,在声明事件时为我们提供了很大的便利,但是缺不方便我们学习和理解事件,下面将展示事件的完整声明和简易声明的区别

    2. 事件成员的创建

      public  event SendMessageEventHandler SendMessage;//事件的简略声明格式

      首先,在事件成员的创建中,我们不需要再自己定义事件的添加器和移除器,也不用创建委托字段(注意是委托字段,不是委托类型,委托类型还是要创建的),这看起来十分的简洁,但同时也会让初学者误以为这是一个带有event关键字的委托类型字段

    3. 触发事件的方法

      protected  void EventAction(string name, string message)
              {
      
      
                  
      
                  if (this.SendMessage != null)
                  {
                      MessageEventArgs e = new MessageEventArgs();
                      e.name = name;
                      e.message = message;
      
                      this.SendMessage.Invoke(this, e);
                  }
      
      
              }

      由于简略的声明格式中,不需要我们再创建委托字段,所以这里迫不得已只能用事件的名字来代替,而正常情况下,事件的右边是只能跟+=和-=操作符的,这里为语法糖导致的自相矛盾的地方,也容易让初学者认为事件的右边是能跟别的操作符,加深“事件是字段”这方向的误解。

      使用语法糖进行事件的简易声明时,其实系统自动为我们声明了委托类型的字段,这个字段可以通过反编译的方法看到,

 本篇文章为观看刘铁猛老师的《C#入门详见》的笔记,更详细的内容可以观看刘老师的视频

b站:C#语言入门详解022事件详解(下)_哔哩哔哩_bilibili

youtube:C#语言入门详解(022)——事件详解(下) - YouTube

        ​​                        ​​​​​

猜你喜欢

转载自blog.csdn.net/zsdxdfs/article/details/131566842