zoukankan      html  css  js  c++  java
  • 不具有继承关系的Delegate如何进行类型转换?

    - 引自: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:     }
  • 相关阅读:
    JS产生随机数的几个用法!
    title与alt的区别
    jquery select取值,赋值操作
    DIV+CSS中标签dl dt dd常用的用法
    vi/vim键盘图
    win7系统注册表的权限修改
    win7 链接打印机时提示未知的用户名或错误密码
    关于无法把程序(Adobe Fireworks CS5)添加到打开方式的解决办法
    把网页发送到桌面代码
    iframe多层嵌套时获取元素总结
  • 原文地址:https://www.cnblogs.com/CLR010/p/2752037.html
Copyright © 2011-2022 走看看