编译器是怎么实现事件的?
在MailManager里面用一行定义了一个事件:public event EventHandler<NewMailEventArgs> NewMail;
编译器会将上面一行代码编译为三个部分如下:
// 1. 初始化一个私有的委托变量
private EventHandler<NewMailEventArgs> NewMail = null;
// 2. 将方法注册到事件的public方法add_Xxx (Xxx表示事件名)
public void add_NewMail(EventHandler<NewMailEventArgs> value)
{
// 循环和调用CompareExchange是一种添加委托的线程安全的方式
EventHandler<NewMailEventArgs> prevHandler;
EventHandler<NewMailEventArgs> newMail = this.NewMail;
do {
prevHandler = newMail;
EventHandler<NewMailEventArgs>newHandler =
(EventHandler<NewMailEventArgs>) Delegate.Combine(prevHandler, value);
newMail = Interlocked.CompareExchange<EventHandler<NewMailEventArgs>>(
ref this.NewMail, newHandler, prevHandler);
} while (newMail != prevHandler);
}
// 3. public方法remove_Xxx(Xxx表示方法名)
// 允许方法从事件中注销public void remove_NewMail(EventHandler<NewMailEventArgs> value)
{
EventHandler<NewMailEventArgs> prevHandler;
EventHandler<NewMailEventArgs> newMail = this.NewMail;
do {
prevHandler = newMail;
EventHandler<NewMailEventArgs> newHandler =
(EventHandler<NewMailEventArgs>) Delegate.Remove(prevHandler, value);
newMail = Interlocked.CompareExchange<EventHandler<NewMailEventArgs>>(
ref this.NewMail, newHandler, prevHandler);
} while (newMail != prevHandler);
}
从这里可以看出事件的确是一块语法糖,这里首先定义了一个私有的委托变量,接着是对该对象增加add和remove操作。所以事件是对委托的封装,来限制我们只能对委托进行add和remove操作,外界并不能访问委托变量本身(私有的)。
注:
1.如果Remove一个未添加的方法,Delegate.Remove在内部不会执行任何操作,也不会抛异常,事件的方法集合不会发送变化。
2.在这个里面add和remove方法都是public的,原因是定义event NewMail时是public的,它们的可访问性保持一致。Event成员也可以被定义为static或virtual,此时,编译器生成的add和remove方法也是static或virtual
3.除了上面列举的三个部分,编译器还会生成一个事件定义的入口。该入口包含一些标志位和在事件下的委托类型,以及add和remove访问器的引用。这个信息能够简单的描述抽象的事件概念和访问器方法的联系。
本文导航
- 第1页: 首页
- 第2页: 编译器是怎么实现事件的?
- 第3页: 定义类型监听事件