編譯器是怎么實現(xiàn)事件的?
在MailManager里面用一行定義了一個事件:public event EventHandler<NewMailEventArgs> NewMail;
編譯器會將上面一行代碼編譯為三個部分如下:
// 1. 初始化一個私有的委托變量
private EventHandler<NewMailEventArgs> NewMail = null;
// 2. 將方法注冊到事件的public方法add_Xxx (Xxx表示事件名)
public void add_NewMail(EventHandler<NewMailEventArgs> value)
{
// 循環(huán)和調(diào)用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在內(nèi)部不會執(zhí)行任何操作,也不會拋異常,事件的方法集合不會發(fā)送變化。
2.在這個里面add和remove方法都是public的,原因是定義event NewMail時是public的,它們的可訪問性保持一致。Event成員也可以被定義為static或virtual,此時,編譯器生成的add和remove方法也是static或virtual
3.除了上面列舉的三個部分,編譯器還會生成一個事件定義的入口。該入口包含一些標(biāo)志位和在事件下的委托類型,以及add和remove訪問器的引用。這個信息能夠簡單的描述抽象的事件概念和訪問器方法的聯(lián)系。
本文導(dǎo)航
- 第1頁: 首頁
- 第2頁: 編譯器是怎么實現(xiàn)事件的?
- 第3頁: 定義類型監(jiān)聽事件