事件 #

一、事件概述 #

1.1 什么是事件 #

事件是对象发出的通知,表示发生了某件事情。

1.2 事件特点 #

  • 发布-订阅模式
  • 类型安全
  • 支持多订阅者
  • 封装委托

二、定义事件 #

2.1 基本语法 #

csharp
public class Button
{
    public event EventHandler? Clicked;
    
    public void Click()
    {
        Clicked?.Invoke(this, EventArgs.Empty);
    }
}

var button = new Button();
button.Clicked += (sender, e) =>
{
    Console.WriteLine("按钮被点击");
};

button.Click();

2.2 自定义事件参数 #

csharp
public class PriceChangedEventArgs : EventArgs
{
    public decimal OldPrice { get; }
    public decimal NewPrice { get; }
    
    public PriceChangedEventArgs(decimal oldPrice, decimal newPrice)
    {
        OldPrice = oldPrice;
        NewPrice = newPrice;
    }
}

public class Stock
{
    private decimal _price;
    
    public event EventHandler<PriceChangedEventArgs>? PriceChanged;
    
    public decimal Price
    {
        get => _price;
        set
        {
            if (_price != value)
            {
                var oldPrice = _price;
                _price = value;
                OnPriceChanged(oldPrice, value);
            }
        }
    }
    
    protected virtual void OnPriceChanged(decimal oldPrice, decimal newPrice)
    {
        PriceChanged?.Invoke(this, new PriceChangedEventArgs(oldPrice, newPrice));
    }
}

三、订阅事件 #

3.1 订阅和取消订阅 #

csharp
var stock = new Stock();

EventHandler<PriceChangedEventArgs> handler = (sender, e) =>
{
    Console.WriteLine($"价格从 {e.OldPrice} 变为 {e.NewPrice}");
};

stock.PriceChanged += handler;
stock.Price = 100;

stock.PriceChanged -= handler;

3.2 方法订阅 #

csharp
var stock = new Stock();

stock.PriceChanged += OnPriceChanged;
stock.PriceChanged -= OnPriceChanged;

void OnPriceChanged(object? sender, PriceChangedEventArgs e)
{
    Console.WriteLine($"价格变化: {e.OldPrice} -> {e.NewPrice}");
}

四、标准事件模式 #

4.1 EventHandler #

csharp
public class ProcessCompletedEventArgs : EventArgs
{
    public bool IsSuccessful { get; }
    public string Message { get; }
    
    public ProcessCompletedEventArgs(bool isSuccessful, string message)
    {
        IsSuccessful = isSuccessful;
        Message = message;
    }
}

public class Process
{
    public event EventHandler<ProcessCompletedEventArgs>? ProcessCompleted;
    
    public void Start()
    {
        Console.WriteLine("处理开始...");
        Thread.Sleep(1000);
        
        OnProcessCompleted(true, "处理成功");
    }
    
    protected virtual void OnProcessCompleted(bool isSuccessful, string message)
    {
        ProcessCompleted?.Invoke(this, new ProcessCompletedEventArgs(isSuccessful, message));
    }
}

4.2 线程安全触发 #

csharp
public class SafeEventPublisher
{
    public event EventHandler? SomethingHappened;
    
    public void RaiseEvent()
    {
        var handler = Volatile.Read(ref SomethingHappened);
        handler?.Invoke(this, EventArgs.Empty);
    }
}

五、事件访问器 #

5.1 自定义事件访问器 #

csharp
public class CustomEventPublisher
{
    private EventHandler? _myEvent;
    
    public event EventHandler MyEvent
    {
        add
        {
            lock (this)
            {
                _myEvent += value;
            }
        }
        remove
        {
            lock (this)
            {
                _myEvent -= value;
            }
        }
    }
    
    protected virtual void OnMyEvent()
    {
        _myEvent?.Invoke(this, EventArgs.Empty);
    }
}

六、实战示例 #

6.1 文件监控器 #

csharp
public class FileMonitor
{
    public event EventHandler<FileChangedEventArgs>? FileChanged;
    
    private readonly FileSystemWatcher _watcher;
    
    public FileMonitor(string path)
    {
        _watcher = new FileSystemWatcher(path)
        {
            EnableRaisingEvents = true
        };
        
        _watcher.Changed += OnFileChanged;
        _watcher.Created += OnFileChanged;
        _watcher.Deleted += OnFileChanged;
    }
    
    private void OnFileChanged(object sender, FileSystemEventArgs e)
    {
        FileChanged?.Invoke(this, new FileChangedEventArgs(e.FullPath, e.ChangeType));
    }
}

public class FileChangedEventArgs : EventArgs
{
    public string FilePath { get; }
    public WatcherChangeTypes ChangeType { get; }
    
    public FileChangedEventArgs(string filePath, WatcherChangeTypes changeType)
    {
        FilePath = filePath;
        ChangeType = changeType;
    }
}

6.2 进度报告 #

csharp
public class ProgressReporter
{
    public event EventHandler<ProgressEventArgs>? ProgressChanged;
    
    public async Task ProcessAsync(int total)
    {
        for (int i = 0; i <= total; i++)
        {
            await Task.Delay(100);
            OnProgressChanged(i, total);
        }
    }
    
    protected virtual void OnProgressChanged(int current, int total)
    {
        var percent = (double)current / total * 100;
        ProgressChanged?.Invoke(this, new ProgressEventArgs(current, total, percent));
    }
}

public class ProgressEventArgs : EventArgs
{
    public int Current { get; }
    public int Total { get; }
    public double Percent { get; }
    
    public ProgressEventArgs(int current, int total, double percent)
    {
        Current = current;
        Total = total;
        Percent = percent;
    }
}

七、总结 #

事件要点:

要点 说明
event 定义事件
EventHandler 标准委托
EventArgs 事件参数
+= -= 订阅取消
Invoke 触发事件

下一步,让我们学习Lambda表达式!

最后更新:2026-03-26