前言
通過(guò)放射,可以在運(yùn)行時(shí)獲得.NET中每一個(gè)類(lèi)型(包括類(lèi)、結(jié)構(gòu)、委托、接口和枚舉等)的成員,包括方法、屬性、事件,以及構(gòu)造函數(shù)等。還可以獲得每個(gè)成員的名稱(chēng)、限定符和參數(shù)等。有了反射,即可對(duì)每一個(gè)類(lèi)型了如指掌。如果獲得了構(gòu)造函數(shù)的信息,即可直接創(chuàng)建對(duì)象,即使這個(gè)對(duì)象的類(lèi)型在編譯時(shí)還不知道。那么如何注冊(cè)事件呢?
本文將介紹如何使用反射注冊(cè)事件。下面話不多說(shuō)了,來(lái)一起看看看詳細(xì)的介紹吧
不使用反射
例如,我們希望反射的類(lèi)型是這樣的:
public class Walterlv { public event EventHandler BlogPublished; }
那么只需要使用如下代碼即可完成事件的注冊(cè):
var walterlv = new Walterlv(); walterlv += Walterlv_BlogPublished;
public void Walterlv_BlogPublished(object sender, EventHandler handler) { }
使用反射
而如果使用反射,則是:
var walterlv = new Walterlv(); var eventInfo = typeof(Walterlv).GetEvent(nameof(BlogPublished)); var handler = new EventHandler(Walterlv_BlogPublished); eventInfo.AddEventHandler(walterlv, handler);
當(dāng)然,實(shí)際使用的時(shí)候,如果能訪問(wèn)到 Walterlv 類(lèi)型,當(dāng)然也不會(huì)去用到反射,所以通常情況是這樣的:
public void AddHandler<T>(T instance, string eventName, EventHandler handler) { var eventInfo = instance.GetType().GetEvent(eventName); eventInfo.AddEventHandler(instance, handler); }
安全地使用反射
雖然以上方式使用了反射成功注冊(cè)了事件,但實(shí)際上我們的參數(shù)中傳入了一個(gè)特定類(lèi)型的委托 EventHandler。實(shí)際上事件的委托種類(lèi)非常多。
在委托中,即便簽名完全相同,也不是同一個(gè)委托類(lèi)型。如果傳入的參數(shù)類(lèi)型改為 EventHandler<EventArgs>
,或者 BlogPublished 事件的類(lèi)型改為 EventHandler<EventHandler>,雖然實(shí)際上這兩個(gè)委托的簽名是兼容的,但其委托類(lèi)型不同,依然是不能互相轉(zhuǎn)換的。你會(huì)在運(yùn)行時(shí)遇到一下異常:
▲ 委托無(wú)法轉(zhuǎn)換
所以我們必須有一些更安全的方式來(lái)注冊(cè)事件。
正常情況下,我們轉(zhuǎn)換一個(gè)簽名兼容的委托是使用構(gòu)造函數(shù):
public EventHandler ConvertDelegate(EventHandler<EventArgs> handler) { return new EventHandler(handler); }
那么在反射中,我們需要使用 Delegate.CreateDelegate 創(chuàng)建指定類(lèi)型的委托。
public void AddHandler<T>(T instance, string eventName) { var eventInfo = instance.GetType().GetEvent(eventName); var methodInfo = GetType().GetMethod(nameof(Walterlv_BlogPublished)); var @delegate = Delegate.CreateDelegate(eventInfo.EventHandlerType, this, methodInfo); eventInfo.AddEventHandler(instance, @delegate); } public void Walterlv_BlogPublished(object sender, EventHandler handler) { }
這里,Delegate.CreateDelegate
的作用就是執(zhí)行委托類(lèi)型的轉(zhuǎn)換。我在 .NET Core/Framework 創(chuàng)建委托以大幅度提高反射調(diào)用的性能 中也提到過(guò)這個(gè)方法。
參考資料
c# - AddEventHandler using reflection - Stack Overflow
總結(jié)
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com