使用反射,我们可以很容易地在运行时调用一些编译时无法确定的属性、方法等。那么如何注册事件呢?
本文将介绍如何使用反射注册事件。


不使用反射

例如,我们希望反射的类型是这样的:

public class Walterlv
{
public event EventHandler BlogPublished;
}

那么只需要使用如下代码即可完成事件的注册:

var walterlv = new Walterlv();
walterlv += Walterlv_BlogPublished;
public void Walterlv_BlogPublished(object sender, EventHandler handler)
{
}

使用反射

而如果使用反射,则是:

var walterlv = new Walterlv();
var eventInfo = typeof(Walterlv).GetEvent(nameof(BlogPublished));
var handler = new EventHandler(Walterlv_BlogPublished);
eventInfo.AddEventHandler(walterlv, handler);

当然,实际使用的时候,如果能访问到 Walterlv 类型,当然也不会去用到反射,所以通常情况是这样的:

public void AddHandler<T>(T instance, string eventName, EventHandler handler)
{
var eventInfo = instance.GetType().GetEvent(eventName);
eventInfo.AddEventHandler(instance, handler);
}

安全地使用反射

虽然以上方式使用了反射成功注册了事件,但实际上我们的参数中传入了一个特定类型的委托 EventHandler。实际上事件的委托种类非常多。

在委托中,即便签名完全相同,也不是同一个委托类型。如果传入的参数类型改为 EventHandler<EventArgs>,或者 BlogPublished 事件的类型改为 EventHandler<EventHandler>,虽然实际上这两个委托的签名是兼容的,但其委托类型不同,依然是不能互相转换的。你会在运行时遇到一下异常:


▲ 委托无法转换

所以我们必须有一些更安全的方式来注册事件。

正常情况下,我们转换一个签名兼容的委托是使用构造函数:

public EventHandler ConvertDelegate(EventHandler<EventArgs> handler)
{
return new EventHandler(handler);
}

那么在反射中,我们需要使用 Delegate.CreateDelegate 创建指定类型的委托。

public void AddHandler<T>(T instance, string eventName)
{
var eventInfo = instance.GetType().GetEvent(eventName);
var methodInfo = GetType().GetMethod(nameof(Walterlv_BlogPublished));
var @delegate = Delegate.CreateDelegate(eventInfo.EventHandlerType, this, methodInfo);
eventInfo.AddEventHandler(instance, @delegate);
} public void Walterlv_BlogPublished(object sender, EventHandler handler)
{
}

这里,Delegate.CreateDelegate 的作用就是执行委托类型的转换。我在 .NET Core/Framework 创建委托以大幅度提高反射调用的性能 中也提到过这个方法。


参考资料

.NET/C# 使用反射注册事件的更多相关文章

  1. C#-WebForm-WebForm开发基础、如何给控件注册事件?——事件委托写法、http无状态性、三层结构

    (小知识 - xml:可扩展的标记语言 html:超文本标记语言) 一.创建WebForm:新建→网站 此时文件夹中只有一个 config 文件,打开后 二.在项目下右键添加新项 在设计页面中打开 从 ...

  2. 注册事件处理程序onclick和addEventListener、attachEvent

    一.设置HTML标签属性为事件处理程序(注意和下面的设置javascript对象属性为事件处理程序是不同的) 用于设置文档元素事件处理程序属性也能化成对应的HTML标签的属性.如果这样做,属性值应该是 ...

  3. 关于javaScript注册事件传递参数的浅析

    最近这半年作为一个java 程序员,我写的javaScript代码都快比java代码多了,前段时间是给某银行做一个柜员管控系统,在柜员授权这一块功能上,由于柜员的授权需要考虑各方面的因素,比如机构权限 ...

  4. JavaScript DOM高级程序设计 4.3控制事件流和注册事件侦听器--我要坚持到底!

    一.事件流 我们通过下面一个实例,进行说明. <body> <h1>Event Flow</h1> <ul id="nav"> &l ...

  5. Android设备 cocos2dx 骨骼动画注册事件播放音效,退到后台再返回黑屏问题

    最近遇到一个cocos2dx 骨骼动画注册事件播放音效,在骨骼动画播放的时候,按HOME键退到桌面,再次打开游戏的时候,会黑屏. 解决办法如下,可能不是太完美,至少解决了大部分问题. 1.在org.c ...

  6. 为WebBrowser的WEB页的Document注册事件的问题

    原文:为WebBrowser的WEB页的Document注册事件的问题 当使用WebBrowser,并对其装载的Web页建立Document的事件后,WebBrowser里的页面元素都变得难于操作了, ...

  7. jQuery-委托事件和on方法注册事件

    delegate注册委托事件 delegate--代理.委托 事件代理----事件最终不是由$("#first")执行,它只是代理元素 第一个参数:最终发生事件的元素 第二个参数: ...

  8. JQuery的事件委托;jQuery注册事件;jQuery事件解绑

    一.事件 ①事件委托:就是给子元素的父元素或者祖先元素注册一个事件,但是事件的执行者是子元素,委托事件的好处是能够给动态创建出来时元素也加上事件. ②简单事件:就是给自己注册事件自己执行动态创建出来的 ...

  9. 利用反射绑定事件处理程序(C#)

    利用反射绑定事件处理程序(C#) 传统的写法:强类型的情况下 using System;using System.Collections.Generic;using System.Text; usin ...

随机推荐

  1. Websocket、长连接、循环连接

    [转]转自知乎高票回答  https://www.zhihu.com/question/20215561 一.WebSocket是HTML5出的东西(协议),也就是说HTTP协议没有变化,或者说没关系 ...

  2. (15)如何使用Cocos2d-x 3.0制作基于tilemap的游戏:第三部分(完)

    引言 程序截图: 在第二部分教程中,Ray教大家如何在地图中制作可碰撞的区域,如何使用tile属性,如何制作可以拾取的物品以及如何动态修改地图.如何使用“Heads up display”来显示分数. ...

  3. samba创建权限(复制)

    1.今天发现用samba挂载开发过程中,发现别人的权限和我的经常不一致,导致提交git的时候都被提交了,心想应该有哪里有一个统一设置的可以设置用户的默认权限,后来百度之后找到下面的文章,以后创建文件和 ...

  4. Python 日历模块calendar.monthrange 获取某一个月有多少天

    import calendar monthRange = calendar.monthrange(2018, 10) (0, 31) 输出的是一个元组: 第一个元素,数字0是这个月的第一天是星期天(上 ...

  5. excel文件与txt文件互转,并且把excel里的数据导入到oracle中

    一.excel文件转换成txt文件的步骤 a.首先要把excel文件转换成txt文件 1.Excel另存为中已经包含了TXT格式,所以我们可以直接将Excel表格另存为TXT格式,但是最后的效果好像不 ...

  6. 无界面Ubuntu服务器搭建selenium+chromedriver+VNC运行环境

    搭建背景 有时候我们需要把基于selenium的爬虫放到服务器上跑的时候,就需要这样一套运行环境,其中VNC是虚拟的显示模式,用于排查定位线上问题以及实时运行情况. 搭建流程 安装虚拟输出设备:sud ...

  7. Sybase数据库常用sql语言

    Sybase数据库常用sql语言 1,表备份: --table_name1:需要备份的表; table_name2:备份后的表 SELECT * into table_name2 from table ...

  8. POJ 1185 炮兵阵地(状压DP)题解

    思路:和上一篇思路一样,但是这里要求最大能排几个,这里要开三维,记录上次和上上次的状态,再一一判定,状态转移方程为 dp[i][j][k] = max(dp[i][j][k],dp[i - 1][k] ...

  9. OpenDayLight Helium实验三 OpenDaylight二层转发机制实验 2

    鉴于在个人笔记本上虚拟机运行ODL实在太慢,把实验的场景搬到了实验室. 实验上:OpenDayLight Helium实验三 OpenDaylight二层转发机制实验 抓包实验 紧接着,在运行Mini ...

  10. POJ 1061 青蛙的约会(扩展欧几里得算法)

    http://poj.org/problem?id=1061 思路: 搞懂这个扩展欧几里得算法花了不少时间,数论真的是难啊. 含义:找出一对整数,使得ax+by=gcd(a,b). 接下来看这道题目, ...