C# 自定义事件与委托

1. 什么是委托(Delegate)

委托就像是一个"方法容器",它可以存储一个或多个方法。当调用委托时,所有存储在其中的方法都会被执行。

简单委托示例

// 1. 定义一个委托类型
public delegate void SimpleDelegate(string message);

class Program
{
    // 2. 创建一个符合委托签名的方法
    static void ShowMessage(string msg)
    {
        Console.WriteLine("显示消息: " + msg);
    }

    static void Main()
    {
        // 3. 创建委托实例并关联方法
        SimpleDelegate myDelegate = ShowMessage;
        
        // 4. 调用委托
        myDelegate("你好,世界!");
    }
}

2. 什么是事件(Event)

事件是基于委托的,它是一种特殊的委托,主要用于实现"发布-订阅"模式。比如按钮点击事件 - 按钮发布点击事件,其他代码可以订阅这个事件。

简单事件示例

// 1. 定义一个委托类型(事件处理器的签名)
public delegate void ButtonClickHandler(object sender, EventArgs e);

// 2. 创建一个包含事件的类
class Button
{
    // 3. 声明事件
    public event ButtonClickHandler Click;
    
    // 4. 触发事件的方法
    public void OnClick()
    {
        if (Click != null) // 检查是否有订阅者
        {
            Click(this, EventArgs.Empty); // 触发事件
        }
    }
}

class Program
{
    // 5. 事件处理方法
    static void Button_Click(object sender, EventArgs e)
    {
        Console.WriteLine("按钮被点击了!");
    }

    static void Main()
    {
        Button btn = new Button();
        
        // 6. 订阅事件
        btn.Click += Button_Click;
        
        // 7. 模拟按钮点击
        btn.OnClick();
    }
}

3. 自定义事件完整示例

让我们创建一个温度监控器的例子,当温度超过阈值时触发事件:

// 1. 自定义事件参数类
public class TemperatureChangedEventArgs : EventArgs
{
    public double OldTemperature { get; }
    public double NewTemperature { get; }
    public DateTime ChangeTime { get; }

    public TemperatureChangedEventArgs(double oldTemp, double newTemp)
    {
        OldTemperature = oldTemp;
        NewTemperature = newTemp;
        ChangeTime = DateTime.Now;
    }
}

// 2. 定义委托
public delegate void TemperatureChangedHandler(object sender, TemperatureChangedEventArgs e);

// 3. 温度监控器类
class TemperatureMonitor
{
    private double _currentTemperature;
    
    // 4. 声明事件
    public event TemperatureChangedHandler TemperatureChanged;
    
    public double CurrentTemperature
    {
        get { return _currentTemperature; }
        set
        {
            if (_currentTemperature != value)
            {
                double oldTemp = _currentTemperature;
                _currentTemperature = value;
                
                // 5. 触发事件
                OnTemperatureChanged(oldTemp, _currentTemperature);
            }
        }
    }
    
    // 6. 触发事件的方法
    protected virtual void OnTemperatureChanged(double oldTemp, double newTemp)
    {
        TemperatureChanged?.Invoke(this, new TemperatureChangedEventArgs(oldTemp, newTemp));
    }
}

class Program
{
    static void Main()
    {
        TemperatureMonitor monitor = new TemperatureMonitor();
        
        // 7. 订阅事件
        monitor.TemperatureChanged += Monitor_TemperatureChanged;
        
        // 8. 改变温度(会触发事件)
        monitor.CurrentTemperature = 25.0;
        monitor.CurrentTemperature = 30.5;
        monitor.CurrentTemperature = 28.0;
    }

    // 9. 事件处理方法
    private static void Monitor_TemperatureChanged(object sender, TemperatureChangedEventArgs e)
    {
        Console.WriteLine($"温度变化: {e.OldTemperature}°C → {e.NewTemperature}°C");
        Console.WriteLine($"变化时间: {e.ChangeTime}");
        Console.WriteLine("----------------------");
    }
}

4. 使用内置的 EventHandler 委托

.NET 提供了 EventHandler<TEventArgs> 泛型委托,可以简化代码:

class TemperatureMonitor
{
    // 使用内置的 EventHandler 委托
    public event EventHandler<TemperatureChangedEventArgs> TemperatureChanged;
    
    // 其余代码与之前相同...
}

5. 总结

  • 委托:方法的容器,可以存储和调用一个或多个方法

  • 事件:基于委托的机制,用于实现发布-订阅模式

  • 自定义事件步骤

    1. 定义事件参数类(继承自 EventArgs)

    2. 定义委托(或使用内置的 EventHandler)

    3. 在类中声明事件

    4. 编写触发事件的方法

    5. 订阅事件并处理

记住:事件让我们的代码可以"通知"其他部分发生了某些事情,而不需要知道谁会处理这些事件!