.NET事件
1 事件简介
1.1 事件介绍
和委托类似,事件是后期绑定机制。 事件基于委托模型,委托模型遵守观察者设计模式,使订阅者能够向提供方注册并接收相关通知。事件发送方推送事件发生的通知,事件接收器接收该通知并定义对它的响应。
事件是对象用于(向系统中的所有相关组件)广播已发生事情的一种方式。 任何其他组件都可以订阅事件,并在事件引发时得到通知。
1.2 事件的设计目标
事件的设计应该遵循下面的目标:
- 在事件源和事件接收器之间启用非常小的耦合。 这两个组件可能不会由同一个组织编写,甚至可能会通过完全不同的计划进行更新。
- 订阅事件并从同一事件取消订阅应该非常简单。
- 事件源应支持多个事件订阅服务器。 它还应支持不依附任何事件订阅服务器。
2 常见的事件使用
2.1 事件委托签名
1 .NET事件委托的标准签名是:
void OnEventRaised(object sender, EventArgs args);
返回类型为 void。 事件基于委托,而且是多播委托。 对任何事件源都支持多个订阅服务器。 来自方法的单个返回值不会扩展到多个事件订阅服务器。
参数列表包含两种参数:发件人和事件参数。
sender的编译时类型为System.Object,即使有一个始终正确的更底层派生的类型亦是如此。 按照惯例使用object。
第二种参数通常是派生自System.EventArgs的类型。即使事件类型无需任何其他参数,你仍将提供这两种参数。应使用特殊值EventArgs.Empty来表示事件不包含任何附加信息。
2.2 定义并引用事件
要将事件添加到类,最简单的方式是将该事件声明为公共字段,例如:
public event EventHandler<FileFoundArgs> FileFound;
看起来它像在声明一个公共字段,这似乎是一个面向对象的不良实践。 你希望通过属性或方法来保护数据访问。 尽管这看起来像一次不良实践,但通过编译器生成的代码却创建了包装器,使事件对象仅能以安全的方式进行访问。 类似字段的事件上唯一可用的操作是(+=)添加处理程序和(-=)删除操作。
2.3 C#使用事件
- 使用event关键字定义事件:
public event EventHandler<FileListArgs> Progress;
- 使用委托调用语法调用事件处理程序
Progress?.Invoke(this, new FileListArgs(file));
- 通过使用+=运算符订阅事件,处理程序方法通常为前缀“On”,后跟事件名称
EventHandler<FileListArgs> onProgress = (sender, eventArgs) => Console.WriteLine(eventArgs.FoundFile); lister.Progress += OnProgress;
- 使用 -= 运算符取消订阅
lister.Progress -= onProgress;
3 使用事件和委托的区别
3.1 相同的地方
它们都提供了一个后期绑定方案:在该方案中,组件通过调用仅在运行时识别的方法进行通信。
它们都支持单个和多个订阅服务器方法。 这称为单播和多播支持。
二者均支持用于添加和删除处理程序的类似语法。
最后,引发事件和调用委托使用完全相同的方法调用语法。 它们甚至都支持与 ?. 运算符一起使用的相同的 Invoke() 方法语法。
3.2 不同的地方
1 事件的侦听是可选的
在确定要使用的语言功能时,最重要的考虑因素为是否必须具有附加的订阅服务器。 如果你的代码必须调用由订阅服务器提供的代码,则应使用基于委托的设计。 如果你的代码在不调用任何订阅服务器的情况下可完成其所有工作,则应使用基于事件的设计。
2 事件返回值需要委托
用于事件的委托均具有无效的返回类型
3 事件侦听器通常具有较长的生存期
订阅事件后,事件源可能会在程序的整个生存期内引发事件。(当不再需要事件时,可以取消订阅事件。)