C#中的委托和事件

模型:DeepSeek-R1,生成时间:2025 03-06 16:24

委托(Delegate)

本质:类型安全的函数指针(方法引用)

作用:定义方法签名,允许将方法作为参数传递

基础使用

// 1. 声明委托类型
public delegate void MyDelegate(string message);

class Program
{
    // 2. 匹配委托签名的方法
    static void ShowMessage(string msg)
    {
        Console.WriteLine($"Message: {msg}");
    }

    static void Main()
    {
        // 3. 实例化委托
        MyDelegate del = new MyDelegate(ShowMessage);
        
        // 4. 调用委托(会执行绑定的方法)
        del("Hello Delegate!");
        
        // 多播委托示例
        del += AnotherMethod;
        del("Multi-cast!");
    }

    static void AnotherMethod(string text)
    {
        Console.WriteLine($"Another: {text}");
    }
}

委托特点:

  • 类型安全:必须匹配方法签名(参数和返回类型)
  • 多播能力:通过 += 添加多个方法
  • 异步调用:BeginInvoke/EndInvoke(注意:.NET Core 后已不再推荐)

事件(Event)

本质:基于委托的封装,实现发布-订阅模式

作用:提供类型安全的通知机制

标准事件模式

// 发布者类
public class TemperatureMonitor
{
    // 1. 声明事件(基于 EventHandler 委托)
    public event EventHandler<TemperatureChangedEventArgs> TemperatureChanged;

    // 2. 触发事件的方法
    private void OnTemperatureChanged(float newTemp)
    {
        var handlers = TemperatureChanged;
        handlers?.Invoke(this, new TemperatureChangedEventArgs(newTemp));
    }

    // 模拟温度变化
    public void SimulateTemperatureChange(float temp)
    {
        Console.WriteLine($"Temperature updated: {temp}C");
        OnTemperatureChanged(temp);
    }
}

// 自定义事件参数
public class TemperatureChangedEventArgs : EventArgs
{
    public float NewTemperature { get; }

    public TemperatureChangedEventArgs(float temp)
    {
        NewTemperature = temp;
    }
}

// 订阅者类
public class AlertSystem
{
    public void Subscribe(TemperatureMonitor monitor)
    {
        monitor.TemperatureChanged += HandleTemperatureChange;
    }

    private void HandleTemperatureChange(object sender, TemperatureChangedEventArgs e)
    {
        if (e.NewTemperature > 30)
        {
            Console.WriteLine($"ALERT: High temperature ({e.NewTemperature}C)!");
        }
    }
}

// 使用示例
class Program
{
    static void Main()
    {
        var monitor = new TemperatureMonitor();
        var alert = new AlertSystem();
        
        alert.Subscribe(monitor);
        
        monitor.SimulateTemperatureChange(25); // 无警报
        monitor.SimulateTemperatureChange(32); // 触发警报
    }
}

事件特点:

  • 封装性:外部只能通过 +=-= 操作订阅/取消
  • 安全性:防止外部直接调用或覆盖已注册的委托
  • 标准模式:建议使用 EventHandler<TEventArgs> 作为基础委托

委托vs事件的关键区别

特性 委托 事件
调用权限 外部可直接调用 只能在声明类内部触发
多播支持 支持 支持
空值检查 需要手动检查 由事件机制自动处理
封装性 低(公共委托字段有风险) 高(只能通过事件访问)
典型应用场景 回调机制、方法参数 观察者模式、通知系统

实际应用场景

  1. GUI 编程(如按钮点击事件)
  2. 异步操作完成通知
  3. 插件系统的事件通知
  4. 游戏开发中的玩家行为触发
  5. 物联网设备状态监控

最佳实践建议

  1. 总是使用 EventHandler<T> 作为事件基础类型
  2. 事件命名使用动词过去式(如 TemperatureChanged
  3. 触发事件前检查是否为 null
  4. 使用 protected virtual 方法作为事件触发方法
  5. 在事件参数类名使用 EventArgs 后缀

通过理解委托和事件的关系,您可以更好地实现松耦合的代码结构。事件本质上是基于委托的封装,为观察者模式提供了更安全的实现方式。