当前位置: 首页 > news >正文

深入解析:C#中级43、什么是事件

在 C#(以及 .NET 生态)中,事件(Event) 是一种语言级别的机制,用于实现 “当某件事情发生时,通知其他对象” 的行为。它是 观察者模式(Observer Pattern)的内置、类型安全、易用的语法糖

✅ 一句话理解:
事件 = 对象发出的“信号”,其他对象可以“订阅”这个信号,并在信号触发时执行自己的逻辑。


举个生活例子

想象一个 门铃系统

  • 你按门铃(触发事件
  • 屋里的人听到铃声(订阅了事件
  • 他去开门(执行响应逻辑

在这个场景中:

  • 门铃事件发布者(Publisher)
  • 屋里的人事件订阅者(Subscriber)
  • “叮咚”声 就是 事件本身

C# 中事件的核心组成

1. 委托(Delegate)—— 事件的“类型”

事件基于 委托(delegate),委托是一种类型安全的函数指针,定义了回调方法的签名。

// 定义一个委托:无返回值,接受 object 和 EventArgs 参数
public delegate void MyEventHandler(object sender, EventArgs e);

.NET 提供了通用委托 EventHandlerEventHandler<T>,通常不需要自定义。


2. 事件(event)—— 发布者声明的“信号”

在类中使用 event 关键字声明一个事件:

public class Doorbell
{// 声明一个事件(基于 EventHandler)public event EventHandler Ringed;// 触发事件的方法public void Press(){Console.WriteLine("门铃被按了!");OnRinged(); // 调用触发方法}protected virtual void OnRinged(){// 安全调用:检查是否有订阅者Ringed?.Invoke(this, EventArgs.Empty);}
}

3. 订阅者 —— 监听并响应事件

其他类可以通过 += 订阅事件,通过 -= 取消订阅:

public class HomeOwner
{public void OpenDoor(object sender, EventArgs e){Console.WriteLine("主人去开门了!");}
}
// 使用
var doorbell = new Doorbell();
var owner = new HomeOwner();
// 订阅事件
doorbell.Ringed += owner.OpenDoor;
// 触发事件
doorbell.Press();
// 输出:
// 门铃被按了!
// 主人去开门了!

标准事件模式(.NET 约定)

.NET 推荐所有事件遵循以下规范:

要素说明
委托类型使用 EventHandlerEventHandler<TEventArgs>
参数(object sender, EventArgs e)
sender触发事件的对象(如 doorbell
e包含事件相关数据(可继承 EventArgs 扩展)

示例:带数据的自定义事件

// 自定义事件数据
public class TemperatureChangedEventArgs : EventArgs
{public double NewTemperature { get; }public TemperatureChangedEventArgs(double temp) => NewTemperature = temp;
}
public class Thermostat
{public event EventHandler TemperatureChanged;private double _temperature;public double Temperature{get => _temperature;set{_temperature = value;OnTemperatureChanged(new TemperatureChangedEventArgs(value));}}protected virtual void OnTemperatureChanged(TemperatureChangedEventArgs e){TemperatureChanged?.Invoke(this, e);}
}
// 订阅
var thermo = new Thermostat();
thermo.TemperatureChanged += (sender, e) =>
{Console.WriteLine($"温度变为: {e.NewTemperature}°C");
};
thermo.Temperature = 25.5; // 触发事件

✅ 事件 vs 普通委托

特性event普通 delegate 字段
封装性只能在类内部触发(invoke),外部只能 += / -=外部可直接调用或清空
安全性防止误操作(如 myEvent = null容易被意外覆盖
语义明确表示“这是一个可订阅的通知”只是一个函数指针

⚠️ 永远不要把事件暴露为 public delegate 字段!用 event 关键字。


事件在 .NET 中的广泛应用

场景示例
GUI 编程button.Click += OnClick;
异步操作timer.Elapsed += OnTimer;
集合变更ObservableCollection.CollectionChanged
生命周期ASP.NET Core 的 ApplicationStarted
自定义组件自定义控件的状态变化通知

⚠️ 注意事项

1. 避免内存泄漏

如果订阅者生命周期比发布者长,记得取消订阅:

// 不取消可能导致发布者无法被 GC(因为事件持有订阅者引用)
doorbell.Ringed -= owner.OpenDoor;

在 WPF/WinForms 中,UI 控件通常自动处理;但在长期运行的服务中需手动管理。

2. 线程安全

事件调用不是线程安全的。如果可能多线程触发,建议:

var handler = Ringed;
handler?.Invoke(this, EventArgs.Empty);

3. 不要滥用事件

  • 适合 “发生了什么” 的通知(如点击、完成、错误)
  • 不适合 “请求做什么”(应使用方法调用)

事件 vs 观察者模式

手写观察者模式C# 事件
实现方式手动维护观察者列表编译器自动生成
类型安全需要接口约束委托保证签名一致
易用性较繁琐+= / -= 极简
性能略高(直接调用)略低(委托链)
推荐特殊需求绝大多数场景首选

C# 事件就是观察者模式的最佳实践封装!


✅ 总结

关键点说明
事件是什么对象发出的通知信号
如何定义public event EventHandler MyEvent;
如何触发MyEvent?.Invoke(this, EventArgs.Empty);
如何订阅publisher.MyEvent += HandlerMethod;
核心价值解耦 + 异步通知 + 响应式编程基础

记住
“事件不是方法,而是一种契约:‘当我发生变化时,我会告诉你’。”

在 C# 开发中,从 WinForm 按钮点击到 ASP.NET Core 中间件,事件无处不在。掌握它,你就掌握了 .NET 响应式编程的灵魂

使用事件的模式如下

将发送通知的类拥有一个委托类型的事件

想要接收事件通知的对象可以将他们自己的方法附加到此委托。

问题

事件和委托类型字段之间的区别是什么

委托类型的公共字段可以从代码中的任何地方调用

为什么在不需要订阅对象时取消订阅事件是一种良好的做法。

因为只要它被订阅,可观察对象和观察者之间就存在隐藏引用,并且他将阻止垃圾回收器从内存中移除观察者对象。

http://www.jsqmd.com/news/120283/

相关文章:

  • 68
  • 2025年12月男生女生童装书包品牌深度调研报告 - 品牌测评鉴赏家
  • Semantic Kernel使用连接器进行向量搜索
  • Vue.js + Element UI 实战:企业级后台管理系统开发全流程
  • 2025年家长必看!儿童鞋服品牌排行榜前十名权威盘点,这些品牌凭什么征服千万家庭? - 品牌测评鉴赏家
  • 跨境电子商务综合试验区DID(内含七批试验区名单)
  • 0-16岁儿童鞋服品牌全解析:从高端到平价,总有一款适合你家宝贝 - 品牌测评鉴赏家
  • 【漏水定位】基于压力测量和拓扑信息实现的稳健数据驱动漏水定位附Matlab代码
  • 1991-2025年地市级年度科学家数量统计数据
  • 一个基于 .NET MAUI 的开箱即用的 UI 组件库,可快速搭建面向业务的应用程序界面!
  • ESA正式授予Sivers波束成形技术开发合同
  • 2025儿童鞋服品牌Top10揭晓!这些品牌凭什么征服家长? - 品牌测评鉴赏家
  • Ubuntu下Qt应用崩溃自动重启6大方案
  • Java毕设选题推荐:基于springboot的游泳用品专卖店系统的设计与实现泳衣、泳镜、浮板【附源码、mysql、文档、调试+代码讲解+全bao等】
  • 事后诸葛亮分析
  • 宝妈必看!2025高性价比儿童鞋服品牌红榜,安全舒适还省钱 - 品牌测评鉴赏家
  • Java毕设项目推荐-基于Springboot的乡政府管理系统设计与实现基于springboot的村务管理系统的设计与实现【附源码+文档,调试定制服务】
  • 2025年12月男生女生童装鞋子质量评测报告 - 品牌测评鉴赏家
  • 第2章:LangChain大模型工具开发(Agent工具能力)
  • win键盘设置改为类似mac 配置
  • 第196期 TRAE 与 Amazon Kiro 智能体驱动集成开发环境(Agentic IDE)对比 - 详解
  • 基于SpringBoot的智能家居控制系统的设计与实现
  • 再见,Kimi?月活不及豆包 5%,谁是下一个王?
  • SoundFlow 开源 .NET 音频引擎
  • 【课程设计/毕业设计】基于springboot的游泳用品专卖店系统的设计与实现商品入库登记、出库审核、库存预警【附源码、数据库、万字文档】
  • 2025年12月男生女生童装品牌深度解析:加盟优势与市场前景 - 品牌测评鉴赏家
  • 【计算机毕业设计案例】基于Spring Boot的数字乡村治理系统“村事通”设计与实现基于springboot的村务管理系统的设计与实现(程序+文档+讲解+定制)
  • 单向循环链表
  • 宝妈必收藏!高性价比儿童鞋服品牌清单,省钱又省心 - 品牌测评鉴赏家
  • Github项目CICD部署