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

  • Learning hard C#学习笔记——读书笔记 08已关闭评论
  • 181 次浏览
  • A+
所属分类:.NET技术
摘要

在生活中,我们有许多的事件,比如:你的朋友结婚,你就会给他送去祝福,这就是事件之一


1.什么是事件

在生活中,我们有许多的事件,比如:你的朋友结婚,你就会给他送去祝福,这就是事件之一

你朋友结婚就是事件源,你送祝福就是处理事件对应的行为

事件往往会涉及两角色——事件的发布者和事件的订阅者,当某个事件发生之后,事件的发布者会发布消息,事件的订阅者会接收事件发生的通知,并做出相应的处理

2.使用事件

2.1 定义事件

// event关键字 委托类型 public event EventHandler birthday 

事件的定义结构为

访问修饰符 event 委托类型 事件名称 

注意

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

2.2 订阅与取消事件

事件的订阅和取消,和我们昨天说到的委托链的取消和链接相同,因为事件的处理其实就是调用委托包装后的方法

public class Bridegroom {      // 1.自定义委托     public delegate void EventHandler(string msg);     // 2.自定义事件     public event EventHandler MarryEvent;      // 3.发出事件     public void OnMarringComing(string msg) {         // 4.判断是否绑定了事件处理方法         if (MarryEvent != null) {             // 5.触发事件             MarryEvent(msg);         }     }      public static void Main(string[] args) {          Bridegroom bridegroom = new Bridegroom();          Friend friend1 = new Friend("张三");         Friend friend2 = new Friend("李四");         Friend friend3 = new Friend("王五");          // 添加事件的订阅者         /*             这里是给MarryEvent这个事件,绑定委托链             委托链的增加和减少使用的就是 +、-          */         bridegroom.MarryEvent += new EventHandler(friend1.sendMessage);         bridegroom.MarryEvent += new EventHandler(friend2.sendMessage);          // 发出事件         Console.WriteLine("===============================");         bridegroom.OnMarringComing("朋友们,我结婚了!");             bridegroom.OnMarringComing("朋友们,我结婚了!");         Console.Read();     }  }  public class Friend {      private string name;     public string Name { get { return this.name; } set { this.name = value; } }      public Friend(string name)     {         this.name = name;     }      public void sendMessage(string message) {         Console.WriteLine(message);          Console.WriteLine(this.Name+"收到了消息");     } } 

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

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

public class Bridegroom {      // 2.自定义事件     public event EventHandler MarryEvent;      // 3.发出事件     public void OnMarringComing(string msg)     {         // 4.判断是否绑定了事件处理方法         if (MarryEvent != null)         {             Console.WriteLine(msg);             // 5.触发事件             MarryEvent(msg,new EventArgs());         }     }      public static void Main(string[] args)     {          Bridegroom bridegroom = new Bridegroom();          Friend friend1 = new Friend("张三");         Friend friend2 = new Friend("李四");         Friend friend3 = new Friend("王五");          // 添加事件的订阅者         /*             这里是给MarryEvent这个事件,绑定委托链             委托链的增加和减少使用的就是 +、-          */         bridegroom.MarryEvent += new EventHandler(friend1.sendMessage);         bridegroom.MarryEvent += new EventHandler(friend2.sendMessage);          // 发出事件              bridegroom.OnMarringComing("朋友们,我结婚了!");         Console.WriteLine("===============================");         Console.Read();     }  }  public class Friend {      private string name;     public string Name { get { return this.name; } set { this.name = value; } }      public Friend(string name)     {         this.name = name;     }      public void sendMessage(object obj,EventArgs args)     {          Console.WriteLine(this.Name + "收到了消息");     } } 

EventHandler 是 .NET 类库中的预定义的委托类型,用于处理不含事件数据的事件,如果想在事件中包含事件数据,可以通过派生(继承)EventArgs来实现

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

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

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

2.3 扩展EventArgs类

public class MarryArgs : EventArgs {      public string Message;      public MarryArgs(string message)      {         this.Message = message;     }  }  public class Bridegroom {      public delegate void MarryEventHandler(object obj, MarryArgs e);     // 2.自定义事件     public event MarryEventHandler MarryEvent;      // 3.发出事件     public void OnMarringComing(string msg)     {         // 4.判断是否绑定了事件处理方法         if (MarryEvent != null)         {             // 5.触发事件             MarryEvent(this,new MarryArgs(msg));         }     }      public static void Main(string[] args)     {          Bridegroom bridegroom = new Bridegroom();          Friend friend1 = new Friend("张三");         Friend friend2 = new Friend("李四");         Friend friend3 = new Friend("王五");          // 添加事件的订阅者         /*             这里是给MarryEvent这个事件,绑定委托链             委托链的增加和减少使用的就是 +、-          */         bridegroom.MarryEvent += new MarryEventHandler(friend1.sendMessage);         bridegroom.MarryEvent += new MarryEventHandler(friend2.sendMessage);          // 发出事件              bridegroom.OnMarringComing("朋友们,我结婚了!");         Console.WriteLine("===============================");          bridegroom.MarryEvent -= new MarryEventHandler(friend2.sendMessage);         bridegroom.MarryEvent += new MarryEventHandler(friend3.sendMessage);         bridegroom.OnMarringComing("朋友们,我结婚了!");          Console.Read();     }  }  public class Friend {      private string name;     public string Name { get { return this.name; } set { this.name = value; } }      public Friend(string name)     {         this.name = name;     }      public void sendMessage(object obj,MarryArgs args)     {         Console.WriteLine(args.Message);         Console.WriteLine(this.Name + "收到了消息");     } } 

我们可以通过派生的方式,让EventArgs携带事件数据

事件的本质

从事件的执行过程,我们可以看出,事件定义中包含委托,事件和委托到底有什么关系呢?

public class Program {      public delegate void MarryHandler(string msg);      public event MarryHandler OnMarry;      static void Main(string[] args) {         Console.WriteLine("Line");     } } 

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

从IL代码中,我们可以看出,MarryHandler委托被编译成一个名为MarryHandler的类,而OnMarry事件则被编译上图的代码

我们查看add_OnMarry方法,我们发现它其实是调用了 Delegate.Combine() 这个方法,Delegate.Combine() 这个方法是将多个委托组合成为了一个多路广播委托

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

而remove_OnMarry()方法,则是调用了 Delegate.Remove() 这个方法,Delegate.Remove() 这个方法是将委托从多路广播委托中删除

而我们还有个OnMarry的字段定义

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

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

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