跳转到内容

C Sharp 事件订阅

来自代码酷

C#事件订阅[编辑 | 编辑源代码]

简介[编辑 | 编辑源代码]

事件订阅是C#中实现发布-订阅模式的核心机制,允许对象(发布者)通知其他对象(订阅者)状态变化或特定动作的发生。事件基于委托构建,是.NET框架中实现松耦合通信的关键特性,广泛应用于用户界面交互、异步编程和组件化设计。

核心概念[编辑 | 编辑源代码]

事件模型的三要素[编辑 | 编辑源代码]

1. 事件发布者(Publisher):包含事件定义并触发事件的对象。 2. 事件订阅者(Subscriber):通过事件处理器(Event Handler)响应事件的对象。 3. 事件处理器(Delegate):定义事件签名的方法契约。

classDiagram class Publisher{ +event EventHandler MyEvent +RaiseEvent() } class Subscriber{ +HandleEvent() } Publisher --> EventHandler Subscriber ..|> EventHandler

语法详解[编辑 | 编辑源代码]

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

数学表示[编辑 | 编辑源代码]

事件订阅可形式化为: {PublisherEvent=i=1nHandleriHandlerDelegate

实际应用场景[编辑 | 编辑源代码]

  • UI开发:按钮点击、文本框输入
  • 游戏编程:角色受伤、得分更新
  • IoT系统:传感器数据更新
  • 微服务:领域事件通知