完整定义一个事件的方法

  以Mail发送为例:

  1. 定义一个类型用于保存所有需要发送给事件通知接受者的附加信息。
    按.Net框架约定,所有保存事件信息的类型都应该继承自System.EventArgs,且类型的名称应该EventArgs结束。

    public class MailMsgEventArgs : EventArgs
    {
    public readonly string from, to, subject, body;

    public MailMsgEventArgs(string from, string to, string subject, string body)
    {
    this.from = from;
    this.to = to;
    this.subject = subject;
    this.body = body;
    }
    }

  2. 定义一个委托类型,用于指定事件触发时被调用的方法原型。
    按.Net框架约定,委托类型名称应该以EventHandler结束。另外,回调方法的原型应该有一个void返回值,并且接受两个参数。第1个参数为Object类型,指向发送通知的对象。第2个参数为一个继承自EventArgs的类型,其中包括所有通知接受者需要的附加信息。如果我们定义的事件没有需要传给事件接受者的附加信息,便不必定义新的委托类型。直接使用FCL中的System.EventHandler,并将EventArgs.Empty传递给第二个参数即可。EventHandler的原型为:public delegate void EventHandler(object sender, EventArgs e);

    public delegate void MailMsgEventHandler(Object sender, MailMsgEventArgs args);
  3. 定义一个事件成员。
    public event MailMsgEventHandler MailMsg;
  4. 定义一个受保护的虚方法,负责通知事件的登记对象。
    protected virtual void OnMailMsg(MailMsgEventArgs e)
    {
    if(MailMsg != null)
    {
    MailMsg(this, e);
    }
    }
  5. 定义一个方法,将输入转化为期望的事件。
    public void SimulateArrivingMsg(string from, string to, string subject, string body)
    {
    MailMsgEventArgs e = new MailMsgEventArgs(from, to, subject, body);
    OnMailMsg(e);
    }

事件原理分析   

  现在让我们看看定义MailMsg事件时发生了些什么事情?

  编译器在遇到事件定义语句:public event MailMsgEventHandler MailMsg会将这段代码翻译成以下3个构造:

//1.一个被初始化为null的私有委托类型字段
private MailMsgEventHandler MailMsg = null;

//2.一个允许对象登记事件的公有add_*方法
[MethodImplAttribute(MethodImplOptions.Synchronized)]
public void add_MailMsg(MailMsgEventHandler handler)
{
MailMsg = (MailMsgEventHandler)Delegate.Combine(MailMsg, handler);
}

//3.一个允许对象注销事件的公有remove_*方法
[MethodImplAttribute(MethodImplOptions.Synchronized)]
public void remove_MailMsg(MailMsgEventHandler handler)
{
MailMsg = (MailMsgEventHandler)Delegate.Remove(MailMsg, handler);
}

  第1步是构造一个委托类型的字段,该字段引用的是一个委托链表的首部,链表中包含了那些期望在事件发生时被通知的委托对象。当一个侦听者需要登记事件时,它只需将一个委托实例添加到委托链表上就可以了。

  注意:登记和注销事件的方法应用了MethodImplAttribute特性,这个特性使方法被标识为同步方法,这使得它们得以实现线程安全,也就是说多个侦听者可以同时登记或注销事件,而不损坏委托链表。

侦听事件

  登记、注销事件代码示例:

class Fax
{
public Fax(MailManager mm)
{
mm.MailMsg += new MailManager.MailMsgEventHandler(FaxMsg);
    //编译器将该代码转换为:
    //mm.add_MailMsg(new MailManager.MailMsgEventHandler(FaxMsg));
}

private void FaxMsg(object sender, MailManager.MailMsgEventArgs e)
{
........
}

public void Unregister(MailManager mm)
{
mm.MailMsg -= new MailManager.MailMsgEventHandler(FaxMsg);

    //编译器将该代码转换为:
    //mm.remove_MailMsg(new MailManager.MailMsgEventHandler(FaxMsg));
}
}

  当一个对象不再希望接受事件通知时,应该注销该事件。

  注意:只要一个对象仍然登记有另一个对象的事件,该对象就不可能被执行垃圾收集。如果我们的类型实现了IDisposable接口的Dispose方法,我们应该在其内部注销其登记的所有事件。  

转载于:https://www.cnblogs.com/free722/archive/2011/03/27/1997203.html

Microsoft.Net框架程序设计学习笔记(15):事件之原理分析相关推荐

  1. Microsoft.Net框架程序设计学习笔记(11):类型构造器

    除实例构造器外,CLR还支持类型构造器(又称静态构造器.类构造器.类型初始化器).类型构造器用于设置一个类型的初始状态.默认情况下,一个类型中没有定义类型构造器,只能手动定义.且类型构造器不能有任何参 ...

  2. hbase java框架_Hadoop学习笔记—15.HBase框架学习(基础实践篇)

    一.HBase的安装配置 1.1 伪分布模式安装 伪分布模式安装即在一台计算机上部署HBase的各个角色,HMaster.HRegionServer以及ZooKeeper都在一台计算机上来模拟. 首先 ...

  3. Hadoop学习笔记—15.HBase框架学习(基础知识篇)

    Hadoop学习笔记-15.HBase框架学习(基础知识篇) HBase是Apache Hadoop的数据库,能够对大型数据提供随机.实时的读写访问.HBase的目标是存储并处理大型的数据.HBase ...

  4. 条件分歧 java_FORTRAN-95程序设计学习笔记-资源下载人人文库网

    <FORTRAN-95程序设计>学习笔记 FORTRAN 95程序设计学习笔记66RPG gg 目录 FORTRAN 95程序设计学习笔记1基础知识(基础.字符串.FORMAT.隐式.TY ...

  5. php mvc 路由,PHP MVC框架路由学习笔记

    文章主要介绍了PHP MVC框架路由学习笔记的相关资料,需要的朋友可以参考下. 提到PHP开发web,自然离不开开发框架,开发框架为我们提供了灵活的开发方式,MVC层分离,业务解耦等... 第一篇先来 ...

  6. C语言程序设计学习笔记:P1-程序设计与C语言

    本系列博客用于记录学习浙江大学翁恺老师的C语言程序设计,系列笔记链接如下: C语言程序设计学习笔记:P1-程序设计与C语言 C语言程序设计学习笔记:P2-计算 C语言程序设计学习笔记:P3-判断 C语 ...

  7. C++语言学习笔记15:Clean 垃圾清理插件

    C++语言学习笔记15:Clean 垃圾清理插件 对话框 STET1 图片切换功能 导入位图资源 插入图片控件并修改属性 添加消息处理函数 step2 开发思路及类关系图 step3 添加控件及MFC ...

  8. JavaScript高级程序设计学习笔记(三)

    分享一下第五章(引用类型)的笔记,内容比较多,我拆成了两部分,今天这部分是关于Object.Array.Date和RegExp类型的. 以下的笔记是书上一些我以前学习的时候,没有太重视的js基础知识, ...

  9. 面向对象程序设计·学习笔记(1/2)

    面向对象程序设计·学习笔记(1/2) 前言 第1章 类与对象 1.1 用类制造对象 1.2 定义类 1.3 成员变量和成员函数 1.4 对象初始化 第2章 对象交互 2.1 对象交互 2.2 访问属性 ...

最新文章

  1. Docker镜像使用
  2. linux下如何查看系统和内核版本
  3. 详解程序包管理RPM
  4. Canvas实现文字粒子化,并且绕轴旋转(完善)
  5. c语言输入一个数存数组,//从键盘上输入若干整数,并将其存入数组中,并统计输入数据的个...
  6. 打通钉钉+WebHook:日志服务告警升级
  7. 家用电器用户行为分析与事件识别_数据产品指北:用户行为分析平台
  8. plsql中oracle定时任务日志,速掌握一个简单的Oracle定时任务
  9. debian重启ssh服务_VScode链接服务器并配置公钥SSH Keys
  10. 会员注册审核状态更新计算
  11. linux优麒麟iso镜像,国产优麒麟操作系统官方下载
  12. php rrd graph,使用lvs-rrd工具监控存储lvs状态信息
  13. CC2530 Hex文件解析
  14. STM32 HAL OTA 小白教程
  15. java id pid 递归,父子结构数据(id,pid)递归查询所有子id合集和父id合集
  16. 判断一个时间段是否经过了另一个时间段
  17. 图片滑块验证码的解决
  18. python常见的问题
  19. Spring中bean的含义
  20. 全球十大资质正规现货黄金交易平台排名榜单(最新版汇总)

热门文章

  1. 磁力mysql搜索_多功能搜索 搜索系统安装 小说 电影 磁力
  2. h710阵列卡支持最大硬盘_DELL服务器RAID磁盘阵列在线扩容(以H710P阵列卡为例)
  3. npm install packagename 安装失败的解决办法
  4. JAVA语言写的,用java语言写
  5. 外链引入css有哪些方式_快速收录的外链操作技巧
  6. 2014北科计算机原理试题答案,北科_计算机组成原理考题-A卷答案
  7. jquery 获取键值对中最大值_jQuery的AJAX发送数据键值对
  8. linux命令中的cp,Linux高级技术:关于cp命令中拷贝所有的写法
  9. 电大计算机一级b考试试题,电大计算机考试本科试题
  10. 罗盘时钟编码代码_安全研究 | 利用macOS Dock实现代码的持久化执行