-
事件(Event):基于委托的通知机制
事件(Event):基于委托的通知机制
-
事件的核心定义
事件是C#中实现发布-订阅模式的核心工具,它是委托的安全封装。核心特点:
发布者(Publisher):触发事件的对象(如订单系统);
订阅者(Subscriber):监听事件并处理的对象(如邮件服务、短信服务);
安全限制:外部只能通过+=订阅/-=取消订阅事件,不能直vb.net教程C#教程python教程SQL教程access 2010教程接调用或赋值(避免滥用)。
事件的本质是委托的包装器,通过event关键字声明,依赖委托定义事件的签名。 -
事件的基本用法
事件的使用流程分为四步:声明委托→定义事件→订阅事件→触发事件。以下用“订单完成通知”为例说明。
2.1 完整代码实现
csharp
using System;
// -------------------------- 发布者:订单系统 --------------------------
public class Order
{
// 1. 声明委托(或用内置委托Action<string>)
public delegate void OrderCompletedHandler(string orderId);
// 2. 定义事件(基于委托)
public event OrderCompletedHandler OnOrderCompleted;
public string OrderId { get; private set; }
public Order(string orderId)
{
OrderId = orderId;
}
// 触发事件的方法(内部调用)
public void CompleteOrder()
{
Console.WriteLine($"订单[{OrderId}]已完成");
// 3. 触发事件:先判断是否有订阅者(避免NullReferenceException)
OnOrderCompleted?.Invoke(OrderId);
}
}
// -------------------------- 订阅者:邮件服务 --------------------------
public static class EmailService
{
// 事件处理方法(签名与委托匹配)
public static void SendOrderEmail(string orderId)
{
Console.WriteLine($"邮件服务:向用户发送订单[{orderId}]完成通知");
}
}
// -------------------------- 订阅者:短信服务 --------------------------
public static class SmsService
{
public static void SendOrderSms(string orderId)
{
Console.WriteLine($"短信服务:向用户发送订单[{orderId}]完成通知");
}
}
// -------------------------- 测试代码 --------------------------
class Program
{
static void Main()
{
// 创建发布者实例
var order = new Order("ORD2025001");
// 4. 订阅事件:将处理方法绑定到事件
order.OnOrderCompleted += EmailService.SendOrderEmail;
order.OnOrderCompleted += SmsService.SendOrderSms;
// 触发事件
order.CompleteOrder();
// 取消订阅短信服务
order.OnOrderCompleted -= SmsService.SendOrderSms;
Console.WriteLine("
取消短信订阅后再次完成订单:");
order.CompleteOrder();
}
}
2.2 逐行代码讲解
发布者(Order类)
委托声明:OrderCompletedHandler委托定义了事件的签名(接受string参数,无返回值);
事件定义:public event OrderCompletedHandler OnOrderCompleted:用event关键字声明事件,外部只能订阅/取消订阅;
触发事件:OnOrderCompleted?.Invoke(OrderId):?.运算符判断事件是否有订阅者,避免空引用异常;Invoke触发事件,传递订单ID。
订阅者(EmailService/SmsService)
处理方法:SendOrderEmail/SendOrderSms的签名与委托完全匹配,用于接收事件通知。
测试代码
订阅事件:order.OnOrderCompleted += EmailService.SendOrderEmail:将邮件服务的处理方法绑定到事件;
触发事件:order.CompleteOrder():内部触发事件,所有订阅者收到通知;
取消订阅:order.OnOrderCompleted -= SmsService.SendOrderSms:移除短信服务的订阅,后续事件不再通知该服务。
输出结果:
订单[ORD2025001]已完成
邮件服务:向用户发送订单[ORD2025001]完成通知
短信服务:向用户发送订单[ORD2025001]完成通知
取消短信订阅后再次完成订单:
订单[ORD2025001]已完成
邮件服务:向用户发送订单[ORD2025001]完成通知
-
系统事件示例
事件广泛应用于.NET框架中,比如控制台的CancelKeyPress事件(处理Ctrl+C):
csharp
using System;
class Program
{
static void Main()
{
// 订阅控制台取消事件
Console.CancelKeyPress += (sender, e) =>
{
Console.WriteLine("
收到取消信号,正在清理资源...");
e.Cancel = true; // 取消默认终止行为
};
Console.WriteLine("按Ctrl+C测试取消事件...");
while (true) { /* 模拟程序运行 */ }
}
}
说明:当用户按下Ctrl+C时,触发CancelKeyPress事件,执行清理逻辑。
4. 基础知识拓展
4.1 事件vs委托:核心区别
特性 委托(Delegate) 事件(Event)
外部操作 外部可直接调用、赋值、添加/移除方法 外部仅能添加(+=)/移除(-=)方法,不能调用或赋值
安全级别 不安全(外部可随意修改委托指向) 安全(仅允许订阅/取消订阅)
使用场景 直接封装方法,用于回调或多播 发布-订阅模式,用于通知机制
本质 引用类型,直接存储方法列表 委托的封装器,编译器生成add/remove方法
4.2 事件的本质
编译器会将事件转换为私有委托字段和公共add/remove方法。例如:
csharp
// 编译器生成的代码(简化版)
private OrderCompletedHandler _onOrderCompleted;
public event OrderCompletedHandler OnOrderCompleted
{
add { _onOrderCompleted += value; }
remove { _onOrderCompleted -= value; }
}
说明:外部无法直接访问_onOrderCompleted委托字段,只能通过add/remove方法操作,确保安全性。
4.3 观察者模式
事件是C#中观察者模式的实现:
观察者模式:定义对象间的一对多依赖,当一个对象状态变化时,所有依赖它的对象收到通知并自动更新;
对应关系:发布者=被观察者,订阅者=观察者,事件=通知机制。
4.4 弱事件模式
当订阅者的生命周期长于发布者时,可能导致内存泄漏(发布者持有订阅者的引用,无法被GC回收)。弱事件模式通过WeakReference避免此问题,比如.NET的WeakEventManager类。
5. 总结
事件是委托的安全封装,核心用于实现发布-订阅模式:
核心流程:声明委托→定义事件→订阅事件→触发事件;
安全特性:外部仅允许订阅/取消订阅,避免滥用;
应用场景:系统通知、UI交互、异步回调等。
掌握事件是理解C#异步编程、UI开发的关键基础。
6. 练习
实现一个温度传感器系统:
1.发布者:TemperatureSensor类,包含CurrentTemperature属性和TemperatureExceeded事件(委托Action
2.订阅者:AlarmService类,当温度>30℃时触发报警;
3.测试:模拟温度变化,触发事件并验证报警逻辑。
参考代码框架:
csharp
public class TemperatureSensor
{
public delegate void TemperatureExceededHandler(double temp);
public event TemperatureExceededHandler TemperatureExceeded;
private double _currentTemp;
public double CurrentTemperature
{
get => _currentTemp;
set
{
_currentTemp = value;
if (_currentTemp >30) TemperatureExceeded?.Invoke(_currentTemp);
}
}
}
public static class AlarmService
{
public static void TriggerAlarm(double temp)
{
Console.WriteLine($"报警:温度超过阈值!当前温度:{temp}℃");
}
}
// 测试
var sensor = new TemperatureSensor();
sensor.TemperatureExceeded += AlarmService.TriggerAlarm;
sensor.CurrentTemperature = 32; // 触发报警
(本节完)
下一章:LINQ基础:数据查询与操作
(深入讲解LINQ的核心概念、查询语法与方法语法)
本站原创,转载请不明出处:https://www.xin3721.com/ArticlecSharp/c49375.html










