全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

C#中的事件(event)如何使用 - 发布-订阅模式的经典实现

C# 的 event 是对发布-订阅模式的原生支持,本质是受保护的委托字段,编译器自动生成私有委托及线程安全的 add/remove 访问器,确保外部只能订阅/取消订阅,不可直接触发或赋值,保障封装性与安全性。

C# 中的 event 是对发布-订阅(Publish-Subscribe)模式的原生支持,它封装了委托(delegate)的调用逻辑,确保外部代码只能“订阅”或“取消订阅”,不能直接触发或清空事件,从而保障了封装性和安全性。

事件的本质是受保护的委托字段

事件底层基于委托,但比普通委托更严格。声明一个事件时,编译器会自动生成一个私有委托字段,并为 +=-= 提供线程安全的访问器(在 .NET Core/.NET 5+ 中默认使用 Interlocked.CompareExchange 保证原子性)。

例如:

public event EventHandler DataReceived;

等价于:一个私有 EventHandler 字段 + 公开的 add/remove 访问器 —— 外部无法直接赋值(如 DataReceived = null)或调用(如 DataReceived(...)),必须通过类内部触发。

标准写法:定义事件、触发事件、订阅事件

典型三步走,遵循 .NET 命名与设计规范:

  • 定义事件:使用 EventHandler 或自定义委托,参数类型继承自 EventArgs
  • 触发事件:先判空(或用 C# 6 的空条件调用 ?.Invoke()),再调用
  • 订阅事件:用 += 绑定方法(支持 Lambda、本地函数、实例/静态方法)

示例:

public class Sensor
{
  public event EventHandler DataUpdated;

  public void Read() {
    var data = new SensorData { Value = DateTime.Now.Second };
    DataUpdated?.Invoke(this, new SensorDataEventArgs(data));
  }
}

// 使用时:
var sensor = new Sensor();
sensor.DataUpdated += (sender, e) => Console.WriteLine($"新数据:{e.Data.Value}");
sensor.Read();

避免常见陷阱

几个高频出错点,直接影响健壮性:

  • 不判空直接调用:事件没人订阅时为 null,直接 Invoke()NullReferenceException
  • 在多线程中未同步触发:虽然 +=/-= 是线程安全的,但事件字段本身可能被并发修改;若需绝对安全,可用 lockInterlocked 包裹触发逻辑(尤其在旧框架中)
  • 忘记取消订阅导致内存泄漏:尤其在长生命周期对象(如窗体、服务)订阅短生命周期对象事件时,应显式用 -= 解绑,或使用弱事件模式
  • 用字段代替事件暴露委托:如 public EventHandler MyHandler; —— 这破坏封装,外部可随意赋值或调用,不是事件

进阶:自定义事件参数与泛型事件

推荐继承 EventArgs 封装业务数据,语义清晰且符合约定:

public class OrderPlacedEventArgs : EventArgs
{
  public Order Order { get; }
  public DateTime Timestamp { get; }

  public OrderPlacedEventArgs(Order order) : base()
  {
    Order = order;
    Timestamp = DateTime.UtcNow;
  }
}

然后声明:
public event EventHandler OrderPlaced;
这样调用方能明确知道事件携带什么信息,IDE 也能更好推导类型。

如果不想依赖 EventArgs,也可用泛型委托如 Action,但会失去事件的标准语义和工具链支持(如设计器、WPF 路由事件),一般不推荐用于公开 API。

基本上就这些。事件不是语法糖,而是 C# 对松耦合通信的基础设施级支持 —— 写清楚谁发布、谁响应、数据怎么传,剩下的交给语言和运行时。


# c#  # 工具  # 路由  # 封装性  # .net  # gate  # NULL  # 封装  # timestamp  # void  # Lambda  # 继承  # class  # public  # 访问器  # Delegate  # 委托  # Event  # 泛型  # 线程  # 多线程  # var  # 并发  # console  # 对象  # 事件  # this  # ide  # wpf  # 自定义  # 自动生成  # 进阶  # 几个  # 也能  # 没人  # 并为  # 装了  # 绑定 


相关文章: h5在线制作网站电脑版下载,h5网页制作软件?  如何用景安虚拟主机手机版绑定域名建站?  深圳网站制作的公司有哪些,dido官方网站?  唐山网站制作公司有哪些,唐山找工作哪个网站最靠谱?  定制建站流程解析:需求评估与SEO优化功能开发指南  详解免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)  宝塔新建站点为何无法访问?如何排查?  微信推文制作网站有哪些,怎么做微信推文,急?  如何在阿里云高效完成企业建站全流程?  如何在万网自助建站平台快速创建网站?  已有域名和空间如何快速搭建网站?  建站主机如何选?性能与价格怎样平衡?  广州网站建站公司选择指南:建站流程与SEO优化关键词解析  极客网站有哪些,DoNews、36氪、爱范儿、虎嗅、雷锋网、极客公园这些互联网媒体网站有什么差异?  制作无缝贴图网站有哪些,3dmax无缝贴图怎么调?  如何选择域名并搭建高效网站?  东莞专业网站制作公司有哪些,东莞招聘网站哪个好?  韩国网站服务器搭建指南:VPS选购、域名解析与DNS配置推荐  网站制作外包价格怎么算,招聘网站上写的“外包”是什么意思?  在线ppt制作网站有哪些,请推荐几个好的课件下载的网站?  建站中国官网:模板定制+SEO优化+建站流程一站式指南  品牌网站制作公司有哪些,买正品品牌一般去哪个网站买?  上海网站制作网页,上海本地的生活网站有哪些?最好包括生活的各个方面的?  建站之星代理商如何保障技术支持与售后服务?  公司网站制作价格怎么算,公司办个官网需要多少钱?  Swift中swift中的switch 语句  建站之星后台搭建步骤解析:模板选择与产品管理实操指南  如何用VPS主机快速搭建个人网站?  C++如何编写函数模板?(泛型编程入门)  如何规划企业建站流程的关键步骤?  专业网站制作企业网站,如何制作一个企业网站,建设网站的基本步骤有哪些?  香港服务器WordPress建站指南:SEO优化与高效部署策略  专业网站制作服务公司,有哪些网站可以免费发布招聘信息?  ,sp开头的版面叫什么?  制作网站的网址是什么,请问后缀为.com和.com.cn还有.cn的这三种网站是分别是什么类型的网站?  如何用手机制作网站和网页,手机移动端的网站能制作成中英双语的吗?  建站主机选购指南:核心配置优化与品牌推荐方案  如何选择靠谱的建站公司加盟品牌?  定制建站价位费用解析与套餐推荐全攻略  如何快速搭建支持数据库操作的智能建站平台?  常州自助建站:操作简便模板丰富,企业个人快速搭建网站  免费的流程图制作网站有哪些,2025年教师初级职称申报网上流程?  C++中的Pimpl idiom是什么,有什么好处?(隐藏实现)  文字头像制作网站推荐软件,醒图能自动配文字吗?  建站ABC备案流程中有哪些关键注意事项?  企业在线网站设计制作流程,想建设一个属于自己的企业网站,该如何去做?  相册网站制作软件,图片上的网址怎么复制?  建站一年半SEO优化实战指南:核心词挖掘与长尾流量提升策略  完全自定义免费建站平台:主题模板在线生成一站式服务  如何在腾讯云免费申请建站? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。