C Sharp 事件订阅
外观
C#事件订阅[编辑 | 编辑源代码]
简介[编辑 | 编辑源代码]
事件订阅是C#中实现发布-订阅模式的核心机制,允许对象(发布者)通知其他对象(订阅者)状态变化或特定动作的发生。事件基于委托构建,是.NET框架中实现松耦合通信的关键特性,广泛应用于用户界面交互、异步编程和组件化设计。
核心概念[编辑 | 编辑源代码]
事件模型的三要素[编辑 | 编辑源代码]
1. 事件发布者(Publisher):包含事件定义并触发事件的对象。 2. 事件订阅者(Subscriber):通过事件处理器(Event Handler)响应事件的对象。 3. 事件处理器(Delegate):定义事件签名的方法契约。
语法详解[编辑 | 编辑源代码]
1. 定义事件[编辑 | 编辑源代码]
使用`event`关键字声明事件,需指定委托类型(通常用`EventHandler`或其泛型版本):
public class Button
{
// 声明事件
public event EventHandler? Clicked;
}
2. 订阅事件[编辑 | 编辑源代码]
通过`+=`操作符添加事件处理器:
Button button = new Button();
button.Clicked += OnButtonClicked; // 订阅
void OnButtonClicked(object? sender, EventArgs e)
{
Console.WriteLine("按钮被点击!");
}
3. 触发事件[编辑 | 编辑源代码]
在发布者内部调用事件(需进行null检查):
public void RaiseEvent()
{
Clicked?.Invoke(this, EventArgs.Empty);
}
完整示例[编辑 | 编辑源代码]
// 温度监控系统示例
public class TemperatureSensor
{
public event EventHandler<TemperatureChangedEventArgs>? TemperatureChanged;
public void SimulateTemperatureChange()
{
Random rnd = new Random();
double newTemp = rnd.NextDouble() * 100;
TemperatureChanged?.Invoke(this, new TemperatureChangedEventArgs(newTemp));
}
}
public class TemperatureChangedEventArgs : EventArgs
{
public double Temperature { get; }
public TemperatureChangedEventArgs(double temperature) => Temperature = temperature;
}
// 订阅者
public class Display
{
public void Subscribe(TemperatureSensor sensor)
{
sensor.TemperatureChanged += ShowTemperature;
}
private void ShowTemperature(object? sender, TemperatureChangedEventArgs e)
{
Console.WriteLine($"当前温度: {e.Temperature:F1}°C");
}
}
// 使用
var sensor = new TemperatureSensor();
var display = new Display();
display.Subscribe(sensor);
sensor.SimulateTemperatureChange(); // 输出示例:当前温度: 76.3°C
高级主题[编辑 | 编辑源代码]
多播委托[编辑 | 编辑源代码]
事件支持多个订阅者,按添加顺序依次调用:
button.Clicked += Handler1;
button.Clicked += Handler2;
// 触发时 Handler1 → Handler2 顺序执行
取消订阅[编辑 | 编辑源代码]
使用`-=`操作符移除订阅:
button.Clicked -= OnButtonClicked;
匿名方法与Lambda表达式[编辑 | 编辑源代码]
button.Clicked += (sender, e) => Console.WriteLine("匿名处理器");
线程安全模式[编辑 | 编辑源代码]
推荐使用以下模式确保线程安全的事件触发:
EventHandler? handler = TemperatureChanged;
handler?.Invoke(this, e);
设计准则[编辑 | 编辑源代码]
1. 事件命名使用动词短语(如`ValueChanged`) 2. 遵循`EventHandler<TEventArgs>`标准模式 3. 事件参数应继承自`EventArgs` 4. 在类销毁前取消所有订阅(避免内存泄漏)
常见问题[编辑 | 编辑源代码]
Q:事件与委托的区别?[编辑 | 编辑源代码]
A:事件是委托的封装,仅允许:
- 发布者:触发事件
- 订阅者:添加/移除处理器
Q:为什么事件触发前要检查null?[编辑 | 编辑源代码]
A:未订阅的事件为null,直接调用会导致NullReferenceException
。
数学表示[编辑 | 编辑源代码]
事件订阅可形式化为:
实际应用场景[编辑 | 编辑源代码]
- UI开发:按钮点击、文本框输入
- 游戏编程:角色受伤、得分更新
- IoT系统:传感器数据更新
- 微服务:领域事件通知