Emit学习-进阶篇-定义事件

之前在研究如何用Emit为动态类添加事件,本来以为会非常简单,但是却碰到了许多的问题,有些问题在之前的答疑篇中已经提到了,并予以了解决,虽然有些地方自己也不是很明白,但毕竟还是解决了,最后比较我写的IL代码,和系统自动生成的,总有一些地方无法做到一致。特别是在为事件添加add和remove方法时,碰到了许多问题,下面我将针对这些问题进行讲解。按照惯例,先给出要实现的类的C#代码,方便反编译后对照着进行IL代码的书写,代码如下:

public class Publisher
{private bool isStart = false;private Random random = new Random(DateTime.Now.Millisecond);public void Start(){if (!isStart){isStart = true;GenerateRand();}}public void Stop(){isStart = false;}private void GenerateRand(){while (isStart){OnRandGenerated(random.Next(10000));Thread.Sleep(1000);}}#region Eventpublic event EventHandler<RandGeneratedEventArgs> RandGenerated;protected virtual void OnRandGenerated(int rand){RaiseRandGeneratedEvent(rand);}private void RaiseRandGeneratedEvent(int rand){EventHandler<RandGeneratedEventArgs> temp = RandGenerated;if (temp != null){RandGeneratedEventArgs arg = new RandGeneratedEventArgs(rand);temp(this, arg);}}#endregion
}

  首先,我们定义类中的相关字段及方法,这部分使用之前基础篇中提到过的步骤就可以完成,不再累述,但是要指出的一点是,在类中,以如下形式初始化的字段:private Random random = new Random(DateTime.Now.Millisecond);如果初始化的值不是常量,则需要在无参构造函数中对齐进行初始化,否则可以使用FieldBuilder的SetConstant方法进行初始化。

  在定义事件时,发现需要手动添加事件的add和remove方法,在这里面会用到事件的本身,而OpCodes指令中好像也没有加载事件的指令,只有加载字段的指令,然后仔细研究了自动生成的IL代码,发现其中生成了一个与定义的事件的同名的私有字段,然后相关的访问都是通过对这个字段的访问来进行的,于是豁然开朗,看来Reflector果然是个好东西呀!

  当定义事件的add和remove方法时,需要注意,我们平时在C#中使用的都是形如+=、-=这样的形式,但是我用这种方法后发现行不通,最后又是在Reflector的帮助下,发现应该分别使用Delegate的Combine和Remove方法,废话不多说,代码和相关注释如下:

//定义事件,事件的可访问性由和它相关的getset方法决定
EventBuilder randGeneratedEvent = publisherTypeBuilder.DefineEvent("RandGenerated", EventAttributes.None, eventType);MethodBuilder addEventBuilder = publisherTypeBuilder.DefineMethod("add_RandGenerated", MethodAttributes.Public, null, new Type[] { eventType });
//注意在我们使用事件时,使用的是+=操作,但在IL代码中并不是如此,应该使用Delegate.Combine方法
ILGenerator addEventIL = addEventBuilder.GetILGenerator();addEventIL.Emit(OpCodes.Ldarg_0);
addEventIL.Emit(OpCodes.Ldarg_0);
addEventIL.Emit(OpCodes.Ldfld, randGeneratedField);
addEventIL.Emit(OpCodes.Ldarg_1);
addEventIL.Emit(OpCodes.Call, typeof(Delegate).GetMethod("Combine", new Type[] { eventType, eventType }));
//返回的是Delegate类型,所以需要进行转换
addEventIL.Emit(OpCodes.Castclass, eventType);
addEventIL.Emit(OpCodes.Stfld, randGeneratedField);randGeneratedEvent.SetAddOnMethod(addEventBuilder);MethodBuilder removeEventBuilder = publisherTypeBuilder.DefineMethod("remove_RandGenerated", MethodAttributes.Public, null, new Type[] { eventType });
//注意在我们使用事件时,使用的是-=操作,但在IL代码中并不是如此,应该使用Delegate.Remove方法
ILGenerator removeEventIL = removeEventBuilder.GetILGenerator();removeEventIL.Emit(OpCodes.Ldarg_0);
removeEventIL.Emit(OpCodes.Ldarg_0);
removeEventIL.Emit(OpCodes.Ldfld, randGeneratedField);
removeEventIL.Emit(OpCodes.Ldarg_1);
removeEventIL.Emit(OpCodes.Call, typeof(Delegate).GetMethod("Remove", new Type[] { eventType, eventType }));
//返回的是Delegate类型,所以需要进行转换
removeEventIL.Emit(OpCodes.Castclass, eventType);
removeEventIL.Emit(OpCodes.Stfld, randGeneratedField);randGeneratedEvent.SetRemoveOnMethod(removeEventBuilder);

posted on 2011-03-28 21:40 林冠逹 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/viclgd/archive/2011/03/28/1998138.html

Emit学习-进阶篇-定义事件相关推荐

  1. Emit学习-进阶篇-异常处理

    异常的处理也是程序中比较重要的一个部分,今天我们就针对用IL书写异常处理代码进行讲解,首先照例给出要实现的类的C#代码,如下: ExceptionHandler class ExceptionHand ...

  2. [Unity 学习] - 进阶篇 - Mesh基础系列1:生成网格

    [Unity 学习] - 进阶篇 - Mesh基础系列1:生成网格 本文并非原创,只是本人的学习记录,原文是由放牛的星星老师翻译Catlike系列教程 链接: https://mp.weixin.qq ...

  3. 深度学习进阶篇-预训练模型[3]:XLNet、BERT、GPT,ELMO的区别优缺点,模型框架、一些Trick、Transformer Encoder等原理详细讲解

    [深度学习入门到进阶]必看系列,含激活函数.优化策略.损失函数.模型调优.归一化算法.卷积模型.序列模型.预训练模型.对抗神经网络等 专栏详细介绍:[深度学习入门到进阶]必看系列,含激活函数.优化策略 ...

  4. Docker学习进阶篇

    学自狂神. 视频地址:https://www.bilibili.com/video/BV1kv411q7Qc?share_source=copy_web 目标: 掌握: docker基础,原理.网络. ...

  5. spring cloud学习进阶篇:Spring Cloud Sleuth + Zipkin 实现分布式跟踪解决方案

    2019独角兽企业重金招聘Python工程师标准>>> 简述 使用 spring cloud 用到最多的是各种rest服务调用,Twitter的Zipkin 是一种实现分布式跟踪解决 ...

  6. Xposed学习进阶篇

    主要类介绍 IXposedHookLoadPackage.java 接口 @Override public void handleLoadPackage(XC_LoadPackage.LoadPack ...

  7. docker从入门到入土(进阶篇)

    Hello~大家好,这里是KOKO! 之前我们学习了docker的基础篇内容,今天我们来深入了解进阶篇的内容. 在学习进阶篇之前,请大家务必保证基础篇的那些常用命令都进行了练习并且已经熟练掌握! do ...

  8. 搞懂正则表达式之进阶篇

    在上一篇博文里我们学习了基础的正则表达式,学会这些还不足以应对工作学习,现在开始学习进阶篇的正则表达式. 目录 1.分组 2.或者 3.分组回溯 4.先行断言 5.后行断言 1.分组 在正则表达式中提 ...

  9. Vue学习笔记进阶篇——Render函数

    本文为转载,原文:Vue学习笔记进阶篇--Render函数 基础 Vue 推荐在绝大多数情况下使用 template 来创建你的 HTML.然而在一些场景中,你真的需要 JavaScript 的完全编 ...

最新文章

  1. Maven的setting.xml配置文件详解(中文)
  2. Vue API(directives) 自定义指令
  3. 网站针对baidu的优化技巧
  4. 深入浅出解释FFT(七)——fft求频谱图和功率谱密度图
  5. 在Ubuntu17.04中遇到无法清空回收站解决方法
  6. python定义一个字典、存储雇员号和姓名_【一点资讯】python后端开发工程师考证试题...
  7. 事件图谱是什么?它能预测未来吗?
  8. tinyxml 内存泄露_tinyxml优化之一
  9. Oracle 自动诊断信息库(Automatic Diagnostic Repository,ADR)
  10. 虚拟交换机软件_千兆交换机如何识别优劣,千兆交换机识别方法!
  11. PHP数据库统计时间戳按天分组输出数据
  12. “他们”将变身为全国最大的房屋租赁供应商
  13. [bigdata-093] drool 规则引擎安装和试用(不全)
  14. 如何从CPU顶盖获取有用信息
  15. mro python_Python之super与MRO
  16. 光耦p621引脚图_p421光耦引脚图和代换
  17. unity3D AR涂涂乐制作浅谈
  18. R包ggalluvial绘制冲击图(alluvial diagram)
  19. 如何判断一个网站地址是否可以安全访问?
  20. 苹果笔记本的end键_苹果电脑快捷键使用 Mac快捷键大全详细介绍

热门文章

  1. pandas 作图 统计_解决pandas 作图无法显示中文的问题
  2. html实现div打印,如何在html div的中间打印/附加从按钮单击的值?
  3. 计算机密码都有什么用,要不是他,你根本不会忘记密码。
  4. android 定时器5秒执行一次,如何在android中每30秒执行一次查询?
  5. 1030 完美数列 (25 分)(c语言)
  6. opengl教程 linux,绘制基本的几何图形 - OpenGL编程学习实战教程_Linux编程_Linux公社-Linux系统门户网站...
  7. linux基础——linux进程间通信(IPC)机制总结
  8. 智能指针weak_ptr
  9. kafka压力测试说明
  10. pygame的一个小问题,未解决