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

Effective C# 原則 22:以事件定義對外介面,實現鬆散耦合通知機制

     編輯:關於C#

事件:基於委派的型別安全通知契約

事件讓型別對外發布通知,任意數量消費者可訂閱處理。發送者無需知曉消費者細節,實現鬆散耦合。

基礎實作:Logger 範例

public class LoggerEventArgs : EventArgs {
    public readonly string Message;
    public readonly int Priority;
    public LoggerEventArgs(int p, string m) { Priority = p; Message = m; }
}

public delegate void AddMessageEventHandler(object sender, LoggerEventArgs msg);

public class Logger {
    private static Logger _theOnly = new Logger();
    public static Logger Singleton => _theOnly;
    private Logger() {}

    public event AddMessageEventHandler Log;

    public void AddMsg(int priority, string msg) {
        var handler = Log; // 複製委派參考,確保執行緒安全
        if (handler != null)
            handler(null, new LoggerEventArgs(priority, msg));
    }
}

關鍵模式: 先複製事件委派至區域變數再檢查/呼叫,防止多執行緒環境下檢查後、呼叫前被移除處理常式。

編譯器自動產生 add/remove 存取子

public event AddMessageEventHandler Log; 等同於:

private AddMessageEventHandler _Log;
public event AddMessageEventHandler Log {
    add { _Log += value; }
    remove { _Log -= value; }
}

消費者訂閱:ConsoleLogger 與 EventLogger

class ConsoleLogger {
    static ConsoleLogger() => Logger.Singleton.Log += Logger_Log;
    private static void Logger_Log(object s, LoggerEventArgs e) 
        => Console.Error.WriteLine($"{e.Priority}:\t{e.Message}");
}

class EventLogger {
    static EventLogger() => Logger.Singleton.Log += Event_Log;
    private static void Event_Log(object s, LoggerEventArgs e) 
        => logDest?.WriteEntry(e.Message, EventLogEntryType.Information, e.Priority);
}

Logger 完全不知消費者存在,消費者自行決定處理方式。

大量事件優化:EventHandlerList

Windows Forms 控制項擁有大量事件,若每個事件皆為欄位會浪費記憶體。System.ComponentModel.EventHandlerList 以鍵值對儲存事件委派,僅在訂閱時建立條目:

public class Logger {
    private static EventHandlerList Handlers = new EventHandlerList();
    public static void AddLogger(string system, AddMessageEventHandler ev) 
        => Handlers[system] = ev;
    public static void AddMsg(string system, int priority, string msg) {
        if (string.IsNullOrEmpty(system)) return;
        var handler = Handlers[system] as AddMessageEventHandler;
        var args = new LoggerEventArgs(priority, msg);
        handler?.Invoke(null, args);
        // 空字串鍵接收所有訊息
        (Handlers[""] as AddMessageEventHandler)?.Invoke(null, args);
    }
}

總結

  • 事件是型別發布動作資訊的標準方式。
  • 委派提供型別安全簽名,編譯器自動管理訂閱/取消。
  • 大量事件場景使用 EventHandlerList 節省記憶體。
  • 發送者與消費者完全解耦,支援動態訂閱與多播。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved