首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 事件處理機制完整解析:委派、事件、EventArgs 與實戰模式

     編輯:關於C語言

核心概念

  • 委派:型別安全的函式指標,封裝方法簽章
  • 事件:基於委派的發佈/訂閱機制,限制外部只能 +=/-=,不可直接調用/賦值
  • EventArgs:攜帶事件資料的容器,慣例繼承 EventArgs

標準事件模式四步驟

1. 宣告委派型別

public delegate void MyHandler1(object sender, MyEventArgs e);
public delegate void MyHandler2(object sender, MyEventArgs e);

2. 定義事件資料類別

public class MyEventArgs : EventArgs
{
    public string Message { get; set; }
}

3. 發布者:宣告事件、觸發邏輯

class Publisher
{
    public event MyHandler1 Event1;
    public event MyHandler2 Event2;

    protected virtual void OnEvent1(MyEventArgs e)
    {
        Event1?.Invoke(this, e); // C# 6.0 null 條件運算子
    }

    protected virtual void OnEvent2(MyEventArgs e)
    {
        Event2?.Invoke(this, e);
    }

    public void TriggerEvents()
    {
        OnEvent1(new MyEventArgs { Message = "Event 1 fired" });
        OnEvent2(new MyEventArgs { Message = "Event 2 fired" });
    }
}

4. 訂閱者:註冊處理器

class Subscriber
{
    public Subscriber(Publisher pub)
    {
        pub.Event1 += OnEvent1Received;
        pub.Event2 += OnEvent2Received;
    }

    void OnEvent1Received(object sender, MyEventArgs e)
        => Console.WriteLine($"Handler1: {e.Message}");

    void OnEvent2Received(object sender, MyEventArgs e)
        => Console.WriteLine($"Handler2: {e.Message}");
}

5. 驅動測試

class Program
{
    static void Main()
    {
        Publisher pub = new Publisher();
        Subscriber sub = new Subscriber(pub);
        pub.TriggerEvents();
    }
}

簡化模式:EventHandler<TEventArgs>

.NET 2.0+ 內建泛型委派,無需自訂委派型別:

public class Publisher
{
    public event EventHandler MyEvent;
    
    protected virtual void OnMyEvent(MyEventArgs e)
        => MyEvent?.Invoke(this, e);
}

進階主題

1. 事件存取器

private EventHandler _myEvent;
public event EventHandler MyEvent
{
    add 
    {
        lock (_lock) _myEvent += value; // 執行緒安全註冊
    }
    remove 
    {
        lock (_lock) _myEvent -= value;
    }
}

2. 弱事件模式

防止訂閱者未解除註冊導致記憶體洩漏,使用 WeakReference 或 WeakEventManager (WPF)。

3. 非同步事件

public event Func AsyncEvent;
async Task TriggerAsync()
{
    var tasks = AsyncEvent?.GetInvocationList()
        .Cast>()
        .Select(h => h(this, new MyEventArgs()));
    if (tasks != null) await Task.WhenAll(tasks);
}

最佳實踐清單

  • 事件命名用動詞過去式:Clicked、Saved、LoadingCompleted
  • 引數類別命名以 EventArgs 結尾
  • 發布者提供 protected virtual OnXxx 方法供衍生類擴展
  • 使用 ?.Invoke 簡化 null 檢查
  • 實作 IDisposable 時在 Dispose 中解除所有事件註冊
  • 避免在建構函式中觸發事件 (物件未完全初始化)
  • 考慮 EventHandler<T> 替代自訂委派

常見錯誤

錯誤後果修正
直接賦值 evt = handler覆蓋其他訂閱者使用 +=
外部直接調用 evt()破壞封裝事件只能在類別內部觸發
未解除註冊記憶體洩漏在 Dispose/Unload 中 -=
靜態事件持有實例參考根引用導致 GC 無法回收用弱事件或及時清理
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved