Emit学习-进阶篇-定义事件
之前在研究如何用Emit為動(dòng)態(tài)類添加事件,本來以為會(huì)非常簡(jiǎn)單,但是卻碰到了許多的問題,有些問題在之前的答疑篇中已經(jīng)提到了,并予以了解決,雖然有些地方自己也不是很明白,但畢竟還是解決了,最后比較我寫的IL代碼,和系統(tǒng)自動(dòng)生成的,總有一些地方無法做到一致。特別是在為事件添加add和remove方法時(shí),碰到了許多問題,下面我將針對(duì)這些問題進(jìn)行講解。按照慣例,先給出要實(shí)現(xiàn)的類的C#代碼,方便反編譯后對(duì)照著進(jìn)行IL代碼的書寫,代碼如下:
public class Publisher {private bool isStart = false;private Random random = new Random(DateTime.Now.Millisecond);public void Start(){if (!isStart){isStart = true;GenerateRand();}}public void Stop(){isStart = false;}private void GenerateRand(){while (isStart){OnRandGenerated(random.Next(10000));Thread.Sleep(1000);}}#region Eventpublic event EventHandler<RandGeneratedEventArgs> RandGenerated;protected virtual void OnRandGenerated(int rand){RaiseRandGeneratedEvent(rand);}private void RaiseRandGeneratedEvent(int rand){EventHandler<RandGeneratedEventArgs> temp = RandGenerated;if (temp != null){RandGeneratedEventArgs arg = new RandGeneratedEventArgs(rand);temp(this, arg);}}#endregion }?
首先,我們定義類中的相關(guān)字段及方法,這部分使用之前基礎(chǔ)篇中提到過的步驟就可以完成,不再累述,但是要指出的一點(diǎn)是,在類中,以如下形式初始化的字段:private Random random = new Random(DateTime.Now.Millisecond);如果初始化的值不是常量,則需要在無參構(gòu)造函數(shù)中對(duì)齊進(jìn)行初始化,否則可以使用FieldBuilder的SetConstant方法進(jìn)行初始化。
在定義事件時(shí),發(fā)現(xiàn)需要手動(dòng)添加事件的add和remove方法,在這里面會(huì)用到事件的本身,而OpCodes指令中好像也沒有加載事件的指令,只有加載字段的指令,然后仔細(xì)研究了自動(dòng)生成的IL代碼,發(fā)現(xiàn)其中生成了一個(gè)與定義的事件的同名的私有字段,然后相關(guān)的訪問都是通過對(duì)這個(gè)字段的訪問來進(jìn)行的,于是豁然開朗,看來Reflector果然是個(gè)好東西呀!
當(dāng)定義事件的add和remove方法時(shí),需要注意,我們平時(shí)在C#中使用的都是形如+=、-=這樣的形式,但是我用這種方法后發(fā)現(xiàn)行不通,最后又是在Reflector的幫助下,發(fā)現(xiàn)應(yīng)該分別使用Delegate的Combine和Remove方法,廢話不多說,代碼和相關(guān)注釋如下:
//定義事件,事件的可訪問性由和它相關(guān)的getset方法決定 EventBuilder randGeneratedEvent = publisherTypeBuilder.DefineEvent("RandGenerated", EventAttributes.None, eventType);MethodBuilder addEventBuilder = publisherTypeBuilder.DefineMethod("add_RandGenerated", MethodAttributes.Public, null, new Type[] { eventType }); //注意在我們使用事件時(shí),使用的是+=操作,但在IL代碼中并不是如此,應(yīng)該使用Delegate.Combine方法 ILGenerator addEventIL = addEventBuilder.GetILGenerator();addEventIL.Emit(OpCodes.Ldarg_0); addEventIL.Emit(OpCodes.Ldarg_0); addEventIL.Emit(OpCodes.Ldfld, randGeneratedField); addEventIL.Emit(OpCodes.Ldarg_1); addEventIL.Emit(OpCodes.Call, typeof(Delegate).GetMethod("Combine", new Type[] { eventType, eventType })); //返回的是Delegate類型,所以需要進(jìn)行轉(zhuǎn)換 addEventIL.Emit(OpCodes.Castclass, eventType); addEventIL.Emit(OpCodes.Stfld, randGeneratedField);randGeneratedEvent.SetAddOnMethod(addEventBuilder);MethodBuilder removeEventBuilder = publisherTypeBuilder.DefineMethod("remove_RandGenerated", MethodAttributes.Public, null, new Type[] { eventType }); //注意在我們使用事件時(shí),使用的是-=操作,但在IL代碼中并不是如此,應(yīng)該使用Delegate.Remove方法 ILGenerator removeEventIL = removeEventBuilder.GetILGenerator();removeEventIL.Emit(OpCodes.Ldarg_0); removeEventIL.Emit(OpCodes.Ldarg_0); removeEventIL.Emit(OpCodes.Ldfld, randGeneratedField); removeEventIL.Emit(OpCodes.Ldarg_1); removeEventIL.Emit(OpCodes.Call, typeof(Delegate).GetMethod("Remove", new Type[] { eventType, eventType })); //返回的是Delegate類型,所以需要進(jìn)行轉(zhuǎn)換 removeEventIL.Emit(OpCodes.Castclass, eventType); removeEventIL.Emit(OpCodes.Stfld, randGeneratedField);randGeneratedEvent.SetRemoveOnMethod(removeEventBuilder); posted on 2011-03-28 21:40 林冠逹 閱讀(...) 評(píng)論(...) 編輯 收藏轉(zhuǎn)載于:https://www.cnblogs.com/viclgd/archive/2011/03/28/1998138.html
總結(jié)
以上是生活随笔為你收集整理的Emit学习-进阶篇-定义事件的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 很厉害的交换两个数
- 下一篇: 惠普武汉实习生面试-20110320