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

“协变”、“逆变”与Delegate类型转换

发布时间:2020-12-16 09:08:04 所属栏目:asp.Net 来源:网络整理
导读:我在发表了《Delegate如何进行类型转换?》之后又想到了其他一些相关的东西,除了简单地分析如何通过Emit实现EventHandler的类型转换之外,还加上关于Delegate“协变”与“逆变”的一些东西,算是对前一篇文章的完善。 目录 一、从Delegate的“协变”与“逆

我在发表了《Delegate如何进行类型转换?》之后又想到了其他一些相关的东西,除了简单地分析如何通过Emit实现EventHandler的类型转换之外,还加上关于Delegate“协变”与“逆变”的一些东西,算是对前一篇文章的完善。

目录
一、从Delegate的“协变”与“逆变”说起
二、EventHandler<TEventArgs>是否换一种定义方式更好?
三、“统一的事件注册”能否应用于一般形式?
四、通过Emit实现EventHandler的类型转换
五、最简单的转换方式

一、从Delegate的“协变”与“逆变”说起

根据Delegate“协变”与“逆变”的原理,对于两个具有相同声明的两个Delegate(A和B),如果B的所有输入(输入参数)类是A的子类或者类型相同,而A的输出(返回值、输出参数)类型是B的子类或者类型相同,那么在B能够使用的地方A也能够使用。我们在定义泛型Delegate的时候可以利用C#“协变”与“逆变”,使类型为A对象能够赋值给类型为B的变量。具体来说,我们需要将输出定义为协变体(通过out关键字),而将输入定义为逆变体(通过in关键字)。比如我们熟悉的Func<T,TResult>的定义:

   1: public delegate TResult Func<in T,out TResult>(T arg);

如下面的代码片断所示,自定义类型Bar是Foo的子类,那么我们就可以将一个Func<Foo,Bar> 对象赋值给Func<Bar,Foo>变量。换言之,Func<Bar,Foo>能够使用的地方,Func<Foo,Bar> 就可以使用。

   2: {
   4:     {
   6:         Func<Bar,Foo> GetFooByBar = getBarByFoo;
   8: }
  10: class Bar : Foo { }

二、EventHandler<TEventArgs>是否换一种定义方式更好?

事件(Event)是Delegate一项重要的使用领域,一般情况下事件成员的类型都是EventHandler。如果具有特殊的EventArgs类型,我们倾向于使用泛型的EventHandler<TEventArgs>。EventHandler和EventHandler<TEventArgs>这两个特殊的Delegate类型定义如下,两者是没有任何关系的。

2: void EventHandler<TEventArgs>(
class EventRegistry<T>
   5:         foreach (EventInfo eventInfo in typeof(T).GetEvents())
   7:             eventInfo.AddEventHandler(target,eventHandler);
   9:     }
class BarEventArgs : EventArgs
   3: class BazEventArgs : EventArgs
   5: class QuxEventArgs : EventArgs
   7:? 
   9: {
  11:     event EventHandler<BazEventArgs> Baz;
  13:? 
  15:     {
  17:         null != Baz) Baz(new BazEventArgs());
  19:     }
class Propgram
   6:         EventRegistry<Foo>.Register(foo,Log);
   8:     }
  10:     {
  12:     }


    
  10: }

那么现在我们将Foo类型的三个事件类型定义成普通的Delegage:BarEventHandler、BazEventHandler和QuxEventHandler,实际上我们上面的代码依然可以执行。

void BazEventHandler(void QuxEventHandler( 4:?
   6: {
   8:     event BazEventHandler Baz;
  10: }

四、通过Emit实现EventHandler的类型转换

我们通过Emit的形式实现了这个类型转换。如下面的代码片断所示,实现在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:         }
  12:         MethodInfo invokeMethod = eventHandlerType.GetMethod("Invoke");
  14:         {
  16:             false;
  18:         parameters = invokeMethod.GetParameters();
  20:         {
  23:         typeof(EventArgs).IsAssignableFrom(parameters[1].ParameterType))
  25:               26:         }
  28:     }
  30:     static Delegate Convert(Delegate eventHandler,Type eventHandlerType)
  32:         Guard.ArgumentNotNull(eventHandler,1)">"eventHandler");
  35:         ParameterInfo[] destinationParameters;
  37:         {
  39:         }
  41:         if (eventHandler.GetType() == eventHandlerType)
  43:             return eventHandler;
  45:? 
  47:         if (!IsValidEventHandler(eventHandler.GetType(),1)">out sourceParameters))
  49:             new InvalidOperationException();
  51:         Type[] paramTypes = new Type[destinationParameters.Length + 1];
  53:         for (int i = 0; i < destinationParameters.Length; i++)
  55:             paramTypes[i + 1] = destinationParameters[i].ParameterType;
  57:         DynamicMethod method = new DynamicMethod("WrappedEventHandler",1)">null,paramTypes);
  60:         il.Emit(OpCodes.Ldarg_0);
  62:         il.Emit(OpCodes.Ldarg_2);
  64:         {
  66:         }
  68:         il.Emit(OpCodes.Ret);
  71:? 
  73:     {
  75:     }
   2: {    
   5:         Guard.ArgumentNotNull(eventHandler,1)">"eventHandler");
   7:         return Delegate.CreateDelegate(eventHandlerType,eventHandler.Method);
  11:     {
  14: }

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读