- A+
所属分类:.NET技术
一 发布者和订阅者
很多时候都有这种需求,当一个特定的程序事件发生时,程序的其他部分可以得到该事件已经发生的通知。
发布者/订阅者模式可以满足这种需求。
发布者:发布某个事件的类或结构,其他类可以在该事件发生时得到通知。
订阅者:注册并在事件发生时得到通知的类或结构。
事件处理程序:由订阅者注册到事件的方法,在发布者触发事件时执行。
触发事件:当事件触发时,所有注册到它的方法会被依次调用。
事件包含了一个私有的委托,事件提供了其私有的委托的结构化访问。
二 事件的使用
2.1 声明事件
class Incrementer { //声明一个CoutedADozen事件 public event EventHandler CountedADozen; }
事件声明在一个类中,通过event关键字声明。
需要委托类型的名称(如:EventHandler),任何注册到事件的处理程序都必须与委托相匹配。
事件是成员,事件成员被隐式自动初始为null。
BCL声明了一个叫做EventHandler的委托,专门用于系统事件。
2.2 订阅事件
订阅者向事件添加事件处理程序。对于一个要添加到事件的处理程序来说,它必须具有与事件的委托相同的返回类型和签名。
订阅事件的几种形式:
//订阅事件的几种形式 incrementer.CountedADozen += IncrementDozensCount; //方法引用形式,实例方法 incrementer.CountedADozen += ClassB.CountHandlerB; //方法引用形式,静态方法 incrementer.CountedADozen += new EventHandler(cc.CountHandleC); //委托形式
和委托一样,也可以使用匿名方法和Lambda表达式来添加事件处理程序。
2.3 触发事件
下附简单的包含发布者和订阅者程序。
delegate void Handler(); //声明委托 class Incrementer { public event Handler CountedADozen; //声明事件并发布 public void DoCount() { for (int i = 0; i < 100; i++) { if (i % 10 == 0) { if (CountedADozen != null) { CountedADozen(); //先判断事件是否为null,再触发事件 } // 简化事件触发语法: CountedADozen?.Invoke(); } } } } class Dozens { public int DozensCount { get; private set; } public Dozens(Incrementer incrementer) { incrementer.CountedADozen += IncrementDozensCount; //订阅事件 } //事件处理程序 private void IncrementDozensCount() { DozensCount++; } } class Program { static void Main(string[] args) { var incrementer = new Incrementer(); var dozens = new Dozens(incrementer); incrementer.DoCount(); Console.WriteLine($"Number of dozens = {dozens.DozensCount}"); Console.Read(); } }
2.4 移除事件处理程序
incrementer.CountedADozen -= IncrementDozensCount; //移除事件处理程序
如果一个处理程序向事件注册了多次,那么当执行命令移除处理程序时,将只移除列表中该处理程序的最后一个实例。