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


不使用反射

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

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. 田忌赛马Java解答

    你一定听过田忌赛马的故事吧?     如果3匹马变成1000匹,齐王仍然让他的马按从优到劣的顺序出赛,田忌可以按任意顺序选择他的赛马出赛.赢一局,田忌可以得到200两银子,输一局,田忌就要输掉200两 ...

  2. 001-mybatis框架

    架构分析: 1. 读SqlMapConfig.xml. 当调用与数据库有关的操作的时候,会读SqlMapConfig.xml文件中的信息,里面配置了Mybatis的运行环境信息,加载mapper.xm ...

  3. C++ Primer 5th Edition自学笔记(1)

    好吧,第一次写东西...如何下手呢...(请无视) -------------------------------------------------------------- Chapter 1. ...

  4. 人脸识别技术大总结(1):Face Detection & Alignment

    http://blog.jobbole.com/85783/     首页 最新文章 IT 职场 前端 后端 移动端 数据库 运维 其他技术 - 导航条 - 首页 最新文章 IT 职场 前端 - Ja ...

  5. Putty出现 Network error:Software caused connection abort

    使用centos7.5 用Putty连接使用没多久就会出现 Network error:Software caused connection abort #修改sshd配置文件.修改3项配置即可 vi ...

  6. Coursera SDN M1.1 SDN History: Central Control

    source Structure 1.讨论SDN的时间线,从1980s至今. 2.认识到SDN背后的原则和idea. 3.识别SDN起源的架构主题. NOTE Four Chapter in SDN ...

  7. [转] sql server 跨数据库调用存储过程

    A库存储过程: create PROCEDURE [dbo].[spAAAForTest] ( ) =null , ) =null ) AS BEGIN select N'A' AS a , N'B' ...

  8. UVa 12549 机器人警卫(最小点覆盖)

    https://vjudge.net/problem/UVA-12549 题意: 在一个Y行X列的网格里有空地(.),重要位置(*)和障碍物(#),用最少的机器人看守所有重要位置,每个机器人要放在一个 ...

  9. 构建工具 Ant、Maven和Gradle

    构建工具的作用 依赖管理 测试,打包,发布 主流的构建工具 Ant:提供编译,测试,打包 Maven:在Ant的基础上提供了依赖管理和发布的功能 Gradle:在Maven的基础上使用Groovy管理 ...

  10. Spring MVC文件上传教程 commons-io/commons-uploadfile

    Spring MVC文件上传教程 commons-io/commons-uploadfile 用到的依赖jar包: commons-fileupload 1.3.1 commons-io 2.4 基于 ...