“协变”、“逆变”与Delegate类型转换
我在发表了《Delegate如何进行类型转换?》之后又想到了其他一些相关的东西,除了简单地分析如何通过Emit实现EventHandler的类型转换之外,还加上关于Delegate“协变”与“逆变”的一些东西,算是对前一篇文章的完善。
一、从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: } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- asp.net MVC 权限设计 asp.net MVC 权限设计(续
- 如何使用asp.net获取html select的所选值
- asp.net-mvc – 如何使用ASP.NET 5 MVC保护Web API 6
- asp.net-mvc – 在.aspx上获得MVC Razor青睐.cshtml
- asp.net-mvc – 如何在MVC中完全分离视图和模型
- asp.net-mvc – 如何在ASP.NET WebApi帮助页面中记录可选的
- 使用.NET Core+Docker 开发微服务
- asp.net – 使用外部CSS文件的用户控件
- asp.net AJAX实现无刷新获得数据
- asp.net-mvc – IApplicationBuilder.New()的目的是什么?