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

C# 事件完整指南:委派、訂閱發布模式與最佳實踐

     編輯:關於C#

事件核心概念

事件是委派的封裝,實現「訂閱-發布」模式。類別定義事件,外部物件訂閱 (加入處理器),觸發條件滿足時類別發布 (引發事件)。

最小範例

using System;

class Counter
{
    private int _count;
    public delegate void CountChangedHandler(int newCount); // 委派型別
    public event CountChangedHandler CountChanged;          // 事件

    public int Count
    {
        get => _count;
        set
        {
            if (_count != value)
            {
                _count = value;
                CountChanged?.Invoke(_count); // 引發事件 (C# 6 null 條件運算子)
            }
        }
    }
}

class Program
{
    static void Main()
    {
        var c = new Counter();
        c.CountChanged += OnCountChanged; // 訂閱
        c.Count = 5;  // 輸出: Count changed to 5
        c.Count = 10; // 輸出: Count changed to 10
    }

    static void OnCountChanged(int n) => Console.WriteLine($"Count changed to {n}");
}

關鍵語法細節

delegateevent+=-=?.Invoke()
語法說明
定義事件處理器的簽章 (回傳型別通常為 void)。
關鍵字聲明事件,限制外部只能 +=/-=,不能直接賦值或 Invoke。
訂閱 (加入多播委派調用清單)。
取消訂閱 (移除)。
安全引發 (無訂閱者時不拋 NullReferenceException)。

標準事件模式

.NET Framework 設計指南建議:

public class CustomEventArgs : EventArgs
{
    public string Message { get; }
    public CustomEventArgs(string msg) => Message = msg;
}

public class Publisher
{
    // 1. 事件委派 (慣用 EventHandler<TEventArgs>)
    public event EventHandler<CustomEventArgs> CustomEvent;

    // 2. 受保護虛擬方法 (衍生類可覆寫引發邏輯)
    protected virtual void OnCustomEvent(CustomEventArgs e)
    {
        CustomEvent?.Invoke(this, e); // sender 為 this
    }

    // 3. 業務方法觸發
    public void DoSomething(string msg)
    {
        OnCustomEvent(new CustomEventArgs(msg));
    }
}

進階主題

1. 自訂事件存取器

private EventHandler<CustomEventArgs> _customEvent;
public event EventHandler<CustomEventArgs> CustomEvent
{
    add
    {
        lock (_lock) _customEvent += value; // 執行緒安全訂閱
    }
    remove
    {
        lock (_lock) _customEvent -= value;
    }
}

2. 弱事件模式

防止訂閱者被事件持有者根引用導致記憶體洩漏。使用 WeakReference 或 WPF 的 WeakEventManager。

3. 非同步事件

public event Func AsyncEvent;

protected virtual async Task OnAsyncEventAsync(CustomEventArgs e)
{
    var handlers = AsyncEvent?.GetInvocationList();
    if (handlers != null)
    {
        var tasks = handlers.Select(h => ((Func)h)(e));
        await Task.WhenAll(tasks);
    }
}

常見陷阱與最佳實踐

陷阱解決方案
忘記取消訂閱導致記憶體洩漏實作 IDisposable 在 Dispose 中 -=;或使用弱事件。
事件處理器拋出例外中斷後續處理器手動遍歷 GetInvocationList() 配合 try-catch。
多執行緒競態 (訂閱/引發同時進行)複製委派快照 var handler = Event; handler?.Invoke(...) 或自訂存取器加鎖。
在建構函式中訂閱靜態事件極易洩漏;改用工廠方法或延遲訂閱。

總結

事件是 C# 實現鬆耦合通知機制的核心。遵循標準模式 (EventHandler<T>、OnXxx 虛擬方法)、注意執行緒安全與生命週期管理,能寫出健壯且可維護的事件驅動程式碼。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved