翼度科技»论坛 编程开发 .net 查看内容

Learning hard C#学习笔记——读书笔记 08

9

主题

9

帖子

27

积分

新手上路

Rank: 1

积分
27
1.什么是事件


在生活中,我们有许多的事件,比如:你的朋友结婚,你就会给他送去祝福,这就是事件之一
你朋友结婚就是事件源,你送祝福就是处理事件对应的行为
事件往往会涉及两角色——事件的发布者和事件的订阅者,当某个事件发生之后,事件的发布者会发布消息,事件的订阅者会接收事件发生的通知,并做出相应的处理


2.使用事件


2.1 定义事件

  1. // event关键字 委托类型
  2. public event EventHandler birthday
复制代码
事件的定义结构为
  1. 访问修饰符 event 委托类型 事件名称
复制代码
注意:

  • 修饰符一般定义为public,因为事件订阅者需要对事件进行订阅与取消操作,定义为公共类型可以使得事件对其他类可见
  • 事件的委托类型,既可以是自定义的委托类型,还可以是.NET类库中预定义的EventHanler

2.2 订阅与取消事件


事件的订阅和取消,和我们昨天说到的委托链的取消和链接相同,因为事件的处理其实就是调用委托包装后的方法
  1. public class Bridegroom {
  2.     // 1.自定义委托
  3.     public delegate void EventHandler(string msg);
  4.     // 2.自定义事件
  5.     public event EventHandler MarryEvent;
  6.     // 3.发出事件
  7.     public void OnMarringComing(string msg) {
  8.         // 4.判断是否绑定了事件处理方法
  9.         if (MarryEvent != null) {
  10.             // 5.触发事件
  11.             MarryEvent(msg);
  12.         }
  13.     }
  14.     public static void Main(string[] args) {
  15.         Bridegroom bridegroom = new Bridegroom();
  16.         Friend friend1 = new Friend("张三");
  17.         Friend friend2 = new Friend("李四");
  18.         Friend friend3 = new Friend("王五");
  19.         // 添加事件的订阅者
  20.         /*
  21.             这里是给MarryEvent这个事件,绑定委托链
  22.             委托链的增加和减少使用的就是 +、-
  23.          */
  24.         bridegroom.MarryEvent += new EventHandler(friend1.sendMessage);
  25.         bridegroom.MarryEvent += new EventHandler(friend2.sendMessage);
  26.         // 发出事件
  27.         Console.WriteLine("===============================");
  28.         bridegroom.OnMarringComing("朋友们,我结婚了!");
  29.    
  30.         bridegroom.OnMarringComing("朋友们,我结婚了!");
  31.         Console.Read();
  32.     }
  33. }
  34. public class Friend {
  35.     private string name;
  36.     public string Name { get { return this.name; } set { this.name = value; } }
  37.     public Friend(string name)
  38.     {
  39.         this.name = name;
  40.     }
  41.     public void sendMessage(string message) {
  42.         Console.WriteLine(message);
  43.         Console.WriteLine(this.Name+"收到了消息");
  44.     }
  45. }
复制代码

除了可以使用自定义委托的方式,来定义事件外,还可以使用.NET类库中的预定义的委托类型 EventHandler 来定义事件

  1. public class Bridegroom
  2. {
  3.     // 2.自定义事件
  4.     public event EventHandler MarryEvent;
  5.     // 3.发出事件
  6.     public void OnMarringComing(string msg)
  7.     {
  8.         // 4.判断是否绑定了事件处理方法
  9.         if (MarryEvent != null)
  10.         {
  11.             Console.WriteLine(msg);
  12.             // 5.触发事件
  13.             MarryEvent(msg,new EventArgs());
  14.         }
  15.     }
  16.     public static void Main(string[] args)
  17.     {
  18.         Bridegroom bridegroom = new Bridegroom();
  19.         Friend friend1 = new Friend("张三");
  20.         Friend friend2 = new Friend("李四");
  21.         Friend friend3 = new Friend("王五");
  22.         // 添加事件的订阅者
  23.         /*
  24.             这里是给MarryEvent这个事件,绑定委托链
  25.             委托链的增加和减少使用的就是 +、-
  26.          */
  27.         bridegroom.MarryEvent += new EventHandler(friend1.sendMessage);
  28.         bridegroom.MarryEvent += new EventHandler(friend2.sendMessage);
  29.         // 发出事件
  30.    
  31.         bridegroom.OnMarringComing("朋友们,我结婚了!");
  32.         Console.WriteLine("===============================");
  33.         Console.Read();
  34.     }
  35. }
  36. public class Friend
  37. {
  38.     private string name;
  39.     public string Name { get { return this.name; } set { this.name = value; } }
  40.     public Friend(string name)
  41.     {
  42.         this.name = name;
  43.     }
  44.     public void sendMessage(object obj,EventArgs args)
  45.     {
  46.         Console.WriteLine(this.Name + "收到了消息");
  47.     }
  48. }
复制代码
EventHandler 是 .NET 类库中的预定义的委托类型,用于处理不含事件数据的事件,如果想在事件中包含事件数据,可以通过派生(继承)EventArgs来实现


从EventHandler委托的定义可以看出:

  • 委托的返回类型为void,因此实例化委托类型的方法也需要满足这一点
  • 第一个参数 sender 负责保存对触发事件的对象引用,其类型为object
  • 第二个参数 e 负责保存事件的数据,EventArgs 类也是 .NET 类库中定义的类,它不保存任何数据

2.3 扩展EventArgs类

  1. public class MarryArgs : EventArgs {
  2.     public string Message;
  3.     public MarryArgs(string message)
  4.     {
  5.         this.Message = message;
  6.     }
  7. }
  8. public class Bridegroom
  9. {
  10.     public delegate void MarryEventHandler(object obj, MarryArgs e);
  11.     // 2.自定义事件
  12.     public event MarryEventHandler MarryEvent;
  13.     // 3.发出事件
  14.     public void OnMarringComing(string msg)
  15.     {
  16.         // 4.判断是否绑定了事件处理方法
  17.         if (MarryEvent != null)
  18.         {
  19.             // 5.触发事件
  20.             MarryEvent(this,new MarryArgs(msg));
  21.         }
  22.     }
  23.     public static void Main(string[] args)
  24.     {
  25.         Bridegroom bridegroom = new Bridegroom();
  26.         Friend friend1 = new Friend("张三");
  27.         Friend friend2 = new Friend("李四");
  28.         Friend friend3 = new Friend("王五");
  29.         // 添加事件的订阅者
  30.         /*
  31.             这里是给MarryEvent这个事件,绑定委托链
  32.             委托链的增加和减少使用的就是 +、-
  33.          */
  34.         bridegroom.MarryEvent += new MarryEventHandler(friend1.sendMessage);
  35.         bridegroom.MarryEvent += new MarryEventHandler(friend2.sendMessage);
  36.         // 发出事件
  37.    
  38.         bridegroom.OnMarringComing("朋友们,我结婚了!");
  39.         Console.WriteLine("===============================");
  40.         bridegroom.MarryEvent -= new MarryEventHandler(friend2.sendMessage);
  41.         bridegroom.MarryEvent += new MarryEventHandler(friend3.sendMessage);
  42.         bridegroom.OnMarringComing("朋友们,我结婚了!");
  43.         Console.Read();
  44.     }
  45. }
  46. public class Friend
  47. {
  48.     private string name;
  49.     public string Name { get { return this.name; } set { this.name = value; } }
  50.     public Friend(string name)
  51.     {
  52.         this.name = name;
  53.     }
  54.     public void sendMessage(object obj,MarryArgs args)
  55.     {
  56.         Console.WriteLine(args.Message);
  57.         Console.WriteLine(this.Name + "收到了消息");
  58.     }
  59. }
复制代码
我们可以通过派生的方式,让EventArgs携带事件数据

事件的本质


从事件的执行过程,我们可以看出,事件定义中包含委托,事件和委托到底有什么关系呢?
  1. public class Program {
  2.     public delegate void MarryHandler(string msg);
  3.     public event MarryHandler OnMarry;
  4.     static void Main(string[] args) {
  5.         Console.WriteLine("Line");
  6.     }
  7. }
复制代码


从IL代码中,我们可以看出,MarryHandler委托被编译成一个名为MarryHandler的类,而OnMarry事件则被编译上图的代码
我们查看add_OnMarry方法,我们发现它其实是调用了 Delegate.Combine() 这个方法,Delegate.Combine() 这个方法是将多个委托组合成为了一个多路广播委托


而remove_OnMarry()方法,则是调用了 Delegate.Remove() 这个方法,Delegate.Remove() 这个方法是将委托从多路广播委托中删除
而我们还有个OnMarry的字段定义


我们发现OnMarry字段主要是有一个私有的字段类型为MarryHandler的委托类型

总结:事件的本质,其实就是 C# 中的一个特殊的多路广播委托(我们把链接多个方法的委托称之为多路广播委托),事件默认含有一个委托类型的变量,该变量用于保存对事件处理方法的引用,且该委托类型的变量为私有,只能从定义该时间的类中进行访问


来源:https://www.cnblogs.com/trueasureyuki/archive/2023/07/31/17565469.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具