加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

Delegate如何进行类型转换?

发布时间:2020-12-16 09:05:36 所属栏目:asp.Net 来源:网络整理
导读:我们知道对于两个不具有继承关系的两个类型,如果没有为它们定义转换器,两这之间的类型转换是不允许的,Delegate也是如此。但是有时候我们却希望“兼容”的两种Delegate类型能够进行转换,比较典型的就是表示事件的Delegate。.NET Framework为我们定义了类

我们知道对于两个不具有继承关系的两个类型,如果没有为它们定义转换器,两这之间的类型转换是不允许的,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)
   3:     EventInfo[] events = typeof(T).GetEvents();
   5:     {
   7:     }
    
   2: { }
   4: { }
   6: { }
   8: delegate void BarEventHandler(object sender,BarEventArgs e);
  10: void QuxEventHandler(  11:? 
  13: {
  15:     event BazEventHandler Baz;
  17:        
  19:     {
  21:         null != Baz) Baz(new BazEventArgs());
  23:     }
class Program
   4:     {
   6:         RegisterEventHandler<Foo>(foo,Log);
   8:     }
  10:     void Log(  11:     {
  13:     }        
   1: Foo: BarEventArgs
   3: Foo: QuxEventArgs

实现在EventHandlerConverter的静态方法Convert方法中的EventHandler与兼容Delegate类型之间的转换是通过“Emit”的机制实现,具体的实现逻辑如下面的代码片断所示。IsValidEventHandler方法用于验证指定的类型是否与EventHandler兼容(按照上面提及的标准进行验证),在Convert方法中我们通过Emit的方式创建了一个DynamicMethod 对象,并最终调用CreateDelegate方法将指定的Delegate对象转换成目标Delegate类型。泛型方法Convert<TDelegate>以强类型的方式指定转换的目标类型。

bool IsValidEventHandler(Type eventHandlerType,1)">out ParameterInfo[] parameters)
   6:         if (!typeof(Delegate).IsAssignableFrom(eventHandlerType))
   8:             parameters = new ParameterInfo[0];
  10:         }
  13:         if (invokeMethod.ReturnType != typeof(void))
  15:             parameters = new ParameterInfo[0];
  17:         }
  19:         if (parameters.Length != 2 || parameters[0].ParameterType != object))
  21:               22:         }
  24:         {
  27:         true;
  29:? 
  31:     {
  33:         Guard.ArgumentNotNull(eventHandlerType,1)" id="lnum34">  34:? 
  36:         if (!IsValidEventHandler(eventHandlerType,1)">out destinationParameters))
  38:             throw new InvalidOperationException();
  40:? 
  42:         {
  44:         }
  46:         ParameterInfo[] sourceParameters;
  48:         {
  50:         }
  52:         paramTypes[0] = eventHandler.GetType();
  54:         {
  56:         }
  58:         MethodInfo invoker = paramTypes[0].GetMethod(  59:         ILGenerator il = method.GetILGenerator();
  61:         il.Emit(OpCodes.Ldarg_1);
  63:         if (!sourceParameters[1].ParameterType.IsAssignableFrom(destinationParameters[1].ParameterType))
  65:             il.Emit(OpCodes.Castclass,sourceParameters[1].ParameterType);
  67:         il.Emit(OpCodes.Call,invoker);
  69:         return method.CreateDelegate(eventHandlerType,eventHandler);
  71:? 
  73:     {
  75:     }