-?引自:Artech
我們知道對于兩個不具有繼承關系的兩個類型,如果沒有為它們定義轉換器,兩這之間的類型轉換是不允許的,Delegate也是如此。但是有時候我們卻希望“兼容”的兩種Delegate類型能夠進行轉換,比較典型的就是表示事件的Delegate。.NET?Framework為我們定義了類型EventHandler來表示事件,但是卻沒有規定事件的Delegate類型是EventHandler的子類。原則上講,事件可以是任意類型的Delegate,但是我們使用的事件一般具有如下兩個共同點:
??不具有返回類型,或者返回類型為void;?
?有且只有兩個輸入參數,其一個參數類型為Object,第二個類型是EventArgs的子類。?
如果事件的類型不是EventHandler的子類,我們是不可以將一個EventHandler對象對事件進行注冊的。如果我們能夠將EventHandler對象轉換成事件對應的類型,那么就可以到達這樣的目的:將同一個EventHandler注冊給任意的事件。我們舉個簡單的例子,假設我們具有這樣一個需求:對于指定的某個對象,需要在它每一個事件觸發的時候我們進行響應的日志記錄。具體實現如下面的代碼所示,具體的日志記錄實現在Log方法中,RegisterEventHandler<T>方法中我們通過反射的方式獲取類型T中定義的所有Event,并將指定的EventHandler針對這些事件進行注冊。由于類型可能不一致,我們通過調用自定義的EventHandlerConverter的靜態方法Convert進行類型轉換。[源代碼從這里下載]
?
??1:?static?void?RegisterEventHandler<T>(T?target,?EventHandler?eventHandler)??2:?{??3:???EventInfo[]?events?=?typeof(T).GetEvents();??4:???foreach?(EventInfo?eventInfo?in?events)??5:???{??6:?????eventInfo.AddEventHandler(target,?EventHandlerConverter.Convert(eventHandler,?eventInfo.EventHandlerType));??7:???}??8:?}?
我們通過如下的代碼定義了一個類型Foo,它具有Bar、Baz和Qux三個事件,其Delegate類分別是BarEventHandler、BazEventHandler和QuxEventHandler。當RaiseEvents方法被調用的時候,注冊的三個事件被觸發。
?
??1:?public?class?BarEventArgs?:?EventArgs??2:?{?}??3:?public?class?BazEventArgs?:?EventArgs??4:?{?}??5:?public?class?QuxEventArgs?:?EventArgs??6:?{?}??7:????8:?public?delegate?void?BarEventHandler(object?sender,?BarEventArgs?e);??9:?public?delegate?void?BazEventHandler(object?sender,?BazEventArgs?e);?10:?public?delegate?void?QuxEventHandler(object?sender,?QuxEventArgs?e);?11:???12:?public?class?Foo?13:?{?14:???public?event?BarEventHandler?Bar;?15:???public?event?BazEventHandler?Baz;?16:???public?event?QuxEventHandler?Qux;?17:?????18:???public?void?RaiseEvents()?19:???{?20:?????if?(null?!=?Bar)?Bar(this,?new?BarEventArgs());?21:?????if?(null?!=?Baz)?Baz(this,?new?BazEventArgs());?22:?????if?(null?!=?Qux)?Qux(this,?new?QuxEventArgs());?23:???}?24:?}?
現在我們在Main方法中編寫如下的程序。從輸出結果可以看出,同一個EventHandler是否能夠成功注冊給Foo中不同類型的三個事件。
?
??1:?class?Program??2:?{??3:???static?void?Main(string[]?args)??4:???{??5:?????Foo?foo?=?new?Foo();??6:?????RegisterEventHandler<Foo>(foo,?Log);??7:?????foo.RaiseEvents();??8:???}??9:???10:???static?void?Log(object?sender,?EventArgs?e)?11:???{?12:?????Console.WriteLine("{0}:?{1}",?sender.GetType().Name,?e.GetType().Name);?13:???}?????14:?}?
輸出結果:
?
??1:?Foo:?BarEventArgs??2:?Foo:?BazEventArgs??3:?Foo:?QuxEventArgs?
實現在EventHandlerConverter的靜態方法Convert方法中的EventHandler與兼容Delegate類型之間的轉換是通過“Emit”的機制實現,具體的實現邏輯如下面的代碼片斷所示。IsValidEventHandler方法用于驗證指定的類型是否與EventHandler兼容(按照上面提及的標準進行驗證),在Convert方法中我們通過Emit的方式創建了一個DynamicMethod?對象,并最終調用CreateDelegate方法將指定的Delegate對象轉換成目標Delegate類型。泛型方法Convert<TDelegate>以強類型的方式指定轉換的目標類型。
?
??1:?public?static?class?EventHandlerConverter??2:?{??3:???public?static?bool?IsValidEventHandler(Type?eventHandlerType,?out?ParameterInfo[]?parameters)??4:???{??5:?????Guard.ArgumentNotNull(eventHandlerType,?"eventHandlerType");??6:?????if?(!typeof(Delegate).IsAssignableFrom(eventHandlerType))??7:?????{??8:???????parameters?=?new?ParameterInfo[0];??9:???????returns?false;?10:?????}
轉載于:https://www.cnblogs.com/CLR010/archive/2012/11/02/2752037.html