不具有继承关系的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:     }

转载于:https://www.cnblogs.com/CLR010/archive/2012/11/02/2752037.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/379159.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java属性loadFromXML()方法与示例

属性类loadFromXML()方法 (Properties Class loadFromXML() method) loadFromXML() method is available in java.util package. loadFromXML()方法在java.util包中可用。 loadFromXML() method is used to load all the properties denoted by the XML file on the given inpu…

FLV封装格式的分析

FLV封装格式的分析&#xff0c;各种详细的参数比较多没有详细解释&#xff0c;这是总体的格式分布。详细的参数说明可以参照文档。 以flv格式内封装的音频流是aac、视频流是h264分析&#xff1a; flv文件tag部分截图&#xff1a;可以看到音频TAG、视频TAG是交错存储的

《计算机基础复习》===数据库技术基础

数据库系统三级结构&#xff1a; 数据库系统一般划分为三个抽象级&#xff1a;用户级、概念级、物理级。 1&#xff09;用户级数据库&#xff1a;对应于外模式。它是用户看到和使用的数据库&#xff0c;又称用户视图&#xff1b;用户级数据库主要由外部记录组成&#xff0c;不同…

bs架构 erp 进销存_从依赖经验到用柔性ERP,企业少走了多少弯路?

企业在面对紧急订单时&#xff0c;传统企业将面临两难问题&#xff1a;如不接受紧急订单,可能会导致潜在的顾客丢失,损失市场占有率;接受紧急订单,可能会给企业带来很多管理上的问题,如材料采购、库存管理等。而企业通过信息化手段提升生产计划与控制的柔性&#xff0c;则可从容…

Python---统计《三国演义》中出现次数较高的人物

统计《三国演义》中出现次数较高的人物。 import jieba excludes{"先主","将军","却说","荆州","二人","不可","不能","如此","忽然","下马","喊声","马…

Java RandomAccessFile close()方法与示例

RandomAccessFile类close()方法 (RandomAccessFile Class close() method) close() method is available in java.io package. close()方法在java.io包中可用。 close() method is used to close this RandomAccessFile stream and free all other system resources linked wit…

云端: 小软件大平台,绿色又安全 V0.9 Beta3(090722)

云端 是一个小软件&#xff0c;但又是一个大平台。安装云端之后&#xff0c;再使用其他软件不再需要安装——一点、下载、直接使用&#xff1b;并且&#xff0c;通过虚拟化的运行环境&#xff0c;能够保持系统长久的干净、绿色&#xff0c;并保持软件与系统的安全隔离——此方面…

MGraph图(代码、分析、汇编)

目录:代码&#xff1a;分析&#xff1a;汇编&#xff1a;MGrapth图表示有邻接矩阵的方式构成的图结构。邻接矩阵用两个数组保存数据&#xff0c;一个一维数组存储图中的顶点信息&#xff0c;一个二维数组存储图中边或弧的信息。无向图中的二维数组是个对称矩阵 1.0表示无边&…

java: 程序包lombok不存在_Java开发神器:Lombok 学习指南

点击上方“Java知音”&#xff0c;选择“置顶公众号”技术文章第一时间送达&#xff01;作者&#xff1a;semlinkerwww.segmentfault.com/a/1190000020864572一、Lombok 简介Lombok 是一款 Java 开发插件&#xff0c;使得 Java 开发者可以通过其定义的一些注解来消除业务工程中…

Python---编程检查并判断密码字符串的安全强度

编程检查并判断密码字符串的安全强度 passwordinput("请输入你的密码&#xff1a;") plist(password) x0 for i in p:if i " ":x1 if x1:print("密码格式不对")#密码中不能包含空格 elif password.isdigit()True or password.isalpha()True:#全…

CFUpdate上传控件的使用

一同事找的这个控件&#xff0c;觉得挺不错的&#xff0c;到官方(http://www.access2008.cn/)下载源码后稍加修改 html页面代码&#xff1a; <html xmlns"http://www.w3.org/1999/xhtml" xml:lang"zh_cn" lang"zh_cn"> <head> <m…

observable_Java Observable addObserver()方法与示例

observable可观察的类addObserver()方法 (Observable Class addObserver() method) addObserver() method is available in java.util package. addObserver()方法在java.util包中可用。 addObserver() method is used to insert the given observer (obs) to the bundles of o…

AAC ADTS格式分析

AAC ADTS格式分析&#xff1a; 没有详细的参数说明&#xff0c;只有格式分析。可以查询文档查看详细参数说明。 ADTS的全称是Audio Data Transport Stream。是AAC音频的传输流格 式。AAC音频格式在MPEG-2&#xff08;ISO-13318-7 2003&#xff09;中有定义。AAC后来 又被采用到…

新知道的几个东西

nginx&#xff08;发音同engine x&#xff09;是一款由俄罗斯程序设计师Igor Sysoev所开发轻量级的网页服务器、反向代理服务器以及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器。起初是供俄国大型的入口网站及搜寻引擎Rambler&#xff08;俄文&#xff1a;Рамбл…

台达plc控制伺服电机编程实例_PLC控制伺服电机:控制脉冲的相关计算

伺服电机PLC通过脉冲的方式控制伺服电机时&#xff0c;其输出脉冲与伺服电机的配置应具有一定的对应关系。如&#xff0c;PLC输出多少个脉冲电机旋转一圈&#xff1f;电机旋转一圈移动的距离(或角度)是多少&#xff1f;这里我们以某伺服电机为例进行举例说明&#xff1a;完成对…

linux rm命令详解

用户可以用rm命令删除不需要的文件。该命令的功能为删除一个目录中的一个或多个文件或目录&#xff0c;它也可以将某个目录及其下的所有文件及子目录均删除。对于链接文件&#xff0c;只是断开了链接&#xff0c;原文件保持不变。 rm命令的一般形式为&#xff1a;rm [选项] 文件…

rotateright_Java Long类rotateRight()方法的示例

rotateright长类rotateRight()方法 (Long class rotateRight() method) rotateRight() method is available in java.lang package. rotationRight()方法在java.lang包中可用。 rotateRight() method is used to returns the value generated by rotating the binary 2’s comp…

实验四 Windows程序设计

1&#xff0c;创建Windows窗体应用程序&#xff0c;实现用户登录功能&#xff0c;当输入正确与错误时均给出相应的提示信息&#xff0c;规定用户输入错误次数不能超过3次。&#xff08;源代码运行界面&#xff09; 这里的口令有个小常识&#xff0c;就是显示*&#xff0c;在口令…

最小连通-(代码、分析、汇编)

目录&#xff1a;介绍&#xff1a;代码&#xff1a;分析&#xff1a;汇编&#xff1a;介绍&#xff1a; 一个有 n 个结点的连通图的生成树是原图的极小连通子图&#xff0c;且包含原图中的所有 n 个结点&#xff0c; 并且有保持图连通的最少的边。 最小生成树可以用kruskal&am…

toad dba for oracle 10.5

http://worlddownloads.quest.com.edgesuite.net/Repository/support.quest.com/Toad%20for%20Oracle/10.5/Software/Toad%20DBA%20Suite%20for%20Oracle%2010.5%20Commercial.exe转载于:https://www.cnblogs.com/devbar/archive/2010/07/01/1768986.html