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

C# 事件進階:字典儲存事件實例與自定義事件存取器實作

     編輯:關於C語言

為何需要字典儲存事件?

當類別擁有大量事件但預期大多數不會被訂閱時,為每個事件宣告欄位會浪費記憶體。使用 Dictionary<string, Delegate> 集中儲存可大幅減少記憶體佔用,這是 Component 類別的核心設計模式。

字典儲存事件完整實作

public delegate void EventHandler1(int i);
public delegate void EventHandler2(string s);

public class PropertyEventsSample
{
    // 事件表:鍵為事件名稱,值為委派鏈
    private Dictionary<string, Delegate> eventTable;

    public PropertyEventsSample()
    {
        eventTable = new Dictionary<string, Delegate>();
        eventTable.Add("Event1", null);
        eventTable.Add("Event2", null);
    }

    // Event1 自定義 add/remove 存取器
    public event EventHandler1 Event1
    {
        add
        {
            lock (eventTable)
            {
                eventTable["Event1"] = (EventHandler1)eventTable["Event1"] + value;
            }
        }
        remove
        {
            lock (eventTable)
            {
                eventTable["Event1"] = (EventHandler1)eventTable["Event1"] - value;
            }
        }
    }

    // Event2 同理
    public event EventHandler2 Event2
    {
        add
        {
            lock (eventTable)
            {
                eventTable["Event2"] = (EventHandler2)eventTable["Event2"] + value;
            }
        }
        remove
        {
            lock (eventTable)
            {
                eventTable["Event2"] = (EventHandler2)eventTable["Event2"] - value;
            }
        }
    }

    // 引發事件的受保護方法
    protected void RaiseEvent1(int i)
    {
        if (eventTable["Event1"] is EventHandler1 handler)
            handler(i);
    }

    protected void RaiseEvent2(string s)
    {
        if (eventTable["Event2"] is EventHandler2 handler)
            handler(s);
    }
}

測試驗證

var p = new PropertyEventsSample();
p.Event1 += new EventHandler1(TestClass.Delegate1Method);
p.Event1 += new EventHandler1(TestClass.Delegate1Method); // 重複訂閱
p.Event1 -= new EventHandler1(TestClass.Delegate1Method); // 取消一次
p.RaiseEvent1(2); // 僅觸發一次,輸出: 2

p.Event2 += new EventHandler2(TestClass.Delegate2Method);
p.Event2 += new EventHandler2(TestClass.Delegate2Method);
p.Event2 -= new EventHandler2(TestClass.Delegate2Method);
p.RaiseEvent2("TestString"); // 輸出: TestString

自定義事件存取器:介面事件顯式實作

當類別實作多個介面且包含同名事件時,需使用顯式介面實作並自定義 add/remove:

public interface IDrawingObject
{
    event EventHandler OnDraw; // 繪製前引發
}

public interface IShape
{
    event EventHandler OnDraw; // 繪製後引發
}

public class Shape : IDrawingObject, IShape
{
    // 內部兩個獨立事件
    private event EventHandler PreDrawEvent;
    private event EventHandler PostDrawEvent;
    private readonly object lockObj = new object();

    // 顯式實作 IDrawingObject.OnDraw → 對應 PreDrawEvent
    event EventHandler IDrawingObject.OnDraw
    {
        add
        {
            lock (lockObj) PreDrawEvent += value;
        }
        remove
        {
            lock (lockObj) PreDrawEvent -= value;
        }
    }

    // 顯式實作 IShape.OnDraw → 對應 PostDrawEvent
    event EventHandler IShape.OnDraw
    {
        add
        {
            lock (lockObj) PostDrawEvent += value;
        }
        remove
        {
            lock (lockObj) PostDrawEvent -= value;
        }
    }

    public void Draw()
    {
        // 繪製前事件
        PreDrawEvent?.Invoke(this, EventArgs.Empty);
        Console.WriteLine("Drawing a shape.");
        // 繪製後事件
        PostDrawEvent?.Invoke(this, EventArgs.Empty);
    }
}

訂閱者區分介面事件

var shape = new Shape();

// 訂閱 IDrawingObject.OnDraw (繪製前)
IDrawingObject d = shape;
d.OnDraw += (s, e) => Console.WriteLine("Sub1: 繪製前事件");

// 訂閱 IShape.OnDraw (繪製後)
IShape s = shape;
s.OnDraw += (s, e) => Console.WriteLine("Sub2: 繪製後事件");

shape.Draw();
// 輸出:
// Sub1: 繪製前事件
// Drawing a shape.
// Sub2: 繪製後事件

關鍵設計要點總結

場景解決方案
大量稀疏事件Dictionary<string, Delegate> + 自定義 add/remove
多介面同名事件顯式介面實作 + 內部獨立事件欄位
執行緒安全lock 保護字典/事件欄位操作
引發事件建立暫存委派副本避免競態條件

現代替代方案

.NET 4.5+ 可考慮使用 EventHandlerList(Component 內部即使用此類別),它針對稀疏事件優化,提供 AddHandler/RemoveHandler 方法,比手動管理 Dictionary 更完善。

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