事件,不知道你是否有也这样理解
目录
- 事件的特点。
- 邮件实例及编译器如何对待事件
- 总结
一、事件
public event EventHandler<NewMailInfo> NewMail;
- public 其他类可以根据规则进行注册和注销。
- event 我觉得就是一种标识符,编译器可以进行识别,进而生成相关事件代码。
- EventHander 泛型委托
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
事件是类的成员,它的出现给类提供了一种能力—-通知其他对象发生了什么。
事件是一种特殊的委托。其他对象符合规则的方法可以注册和注销事件的关注。
二、邮件实例
需求:当收到新邮件时,同时通知转发给传真机以及其他机器,使得他们可以根据自己的方式处理新邮件
1、邮件信息类:承载邮件相关信息,继承EventArgs
public class NewMailInfo:EventArgs
{
private readonly string msg, from, to;
public string Msg { get { return msg; } }
public string From { get { return from; } }
public string To { get { return to; } }
public NewMailInfo(string _from, string _to, string _msg)
{
msg = _msg;
to = _to;
from = _from;
}
}
2、邮件管理类:负责接收新邮件,并通知注册的其他类(如:传真机、打印机等)
首先,定义一个处理新邮件方法,将相关信息赋予邮件信息承载类,并调用通知方法。
public void SimulateNewMail(string from, string to, string msg)
{
NewMailInfo e = new NewMailInfo(from, to, msg);
OnNewMail(e);
}
其次,新邮件通知功能,通知其他注册类。
public event EventHandler<NewMailInfo> NewMail;
protected virtual void OnNewMail(NewMailInfo e)
{
EventHandler<NewMailInfo> temp = System.Threading.Interlocked.CompareExchange(ref NewMail, null, null);
if (temp != null)
temp(this, e);
}
当编译器遇检测到 event 关键字时,会将事件:
public event EventHandler MsgEvent;
翻译成三部分:
1、
private EventHandler<NewMailInfo> _newmail = null;
- 委托引用链,用于存储最终注册的方法引用。
- 私有委托,private防止外类的修改。
- 后面的add() 和 remove()方法,用于向这个委托引用链添加和删除引用。
2、
public void add_NewMail(EventHandler<NewMailInfo> value)
{
//当前委托链
EventHandler<NewMailInfo> newmail = this._newmail;
EventHandler<NewMailInfo> prevHandler;
do
{
prevHandler = newmail;
EventHandler<NewMailInfo> newHandler = (EventHandler<NewMailInfo>)Delegate.Combine(prevHandler, value);
newmail = System.Threading.Interlocked.CompareExchange(ref this._newmail, newHandler, prevHandler);
} while (newmail != prevHandler);
}
- 编译器生成add_NewMail(EventHandler<NewMailInfo> value)方法
-
将当前的委托链备份一份。EventHandler<NewMailInfo> newmail = this._newmail;
- 循环体内,EventHandler<NewMailInfo> newHandler = (EventHandler<NewMailInfo>)Delegate.Combine(prevHandler, value);将当前需要注册的方法引用追加到委托链 prevHandler,并生成新的委托链 newHandler
- newmail = System.Threading.Interlocked.CompareExchange(ref this._newmail, newHandler, prevHandler); 当前this._newmail,与prevHandler 引用实例是否一样。如果一样就将 newHandler的值赋值给this._newmail。
3、类似add功能 的remove()方法。
整个邮件管理类就可以这样实现了。

public class MailManager
{
public event EventHandler<NewMailInfo> NewMail;
protected virtual void OnNewMail(NewMailInfo e)
{
EventHandler<NewMailInfo> temp = System.Threading.Interlocked.CompareExchange(ref NewMail, null, null);
if (temp != null)
temp(this, e);
}
public void SimulateNewMail(string from, string to, string msg)
{
NewMailInfo e = new NewMailInfo(from, to, msg);
OnNewMail(e);
}
}
3、其他类如何注册
public class Fax { public Fax(MailManager mm) { mm.NewMail+=FaxMsg; } public void FaxMsg(object sender, NewMailInfo e) { Console.Write(e.Msg+"【来自传真机】"); } }
当前使用+=进行注册,其实也是也是用add()方法进行注册方法引用。
三、总结
- 编译器遇到event这个标志会进行翻译。一个私有的委托,向外开放注册add和注销remove方法。事件只能当前类进行修改,对外只提供注册和注销方法。
- 拥有事件的类在触发事件就会调用这个委托所维护的新的方法列表对方法进行回调,理所当然的拥有了通知其他对象的能力。
- 外部类通过注册事件,可以得到通知,并进行属于自己方式的处理。
更多精彩原创心得,请关注微信公众号: 梯形

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?