C# 事件(event)本質上是觀察者模式的語言級內建實作。本文透過並列代碼對照,展示 delegate/event 如何對應觀察者模式的 Subject、Observer、Attach/Detach、Notify、Update 角色,幫助開發者從設計模式角度理解事件機制。
| 觀察者模式角色 | C# 事件對應 | 說明 |
|---|---|---|
| Subject(被觀察者) | 擁有 event 的類別(如 ListWithChangedEvent) | 維護觀察者清單,狀態改變時觸發通知 |
| Observer(觀察者) | 訂閱事件的類別(如 EventListener) | 實作處理方法(Update),註冊到 Subject |
| Attach | event += handler | 將委派加入調用清單 |
| Detach | event -= handler | 從調用清單移除委派 |
| Notify | OnChanged() 呼叫 event(this, e) | 遍歷調用清單依序執行每個委派 |
| Update | 事件處理方法(ListChanged) | 觀察者回應通知的邏輯 |
| 事件參數 | EventArgs / 自訂 XxxEventArgs | 攜帶狀態變更資訊 |
interface IObserver { void Update(object sender, EventArgs e); }
interface ISubject { void Attach(IObserver o); void Detach(IObserver o); void Notify(); }
class Subject : ISubject
{
private List _obs = new List();
public void Attach(IObserver o) => _obs.Add(o);
public void Detach(IObserver o) => _obs.Remove(o);
public void Notify() => _obs.ForEach(o => o.Update(this, EventArgs.Empty));
}
public delegate void ChangedEventHandler(object sender, EventArgs e);
class ListWithChangedEvent : ArrayList
{
public event ChangedEventHandler Changed; // 事件 = 內建觀察者清單
protected virtual void OnChanged(EventArgs e)
{
Changed?.Invoke(this, e); // Null-conditional 呼叫 = Notify
}
public override int Add(object value)
{
int i = base.Add(value);
OnChanged(EventArgs.Empty); // 狀態改變觸發通知
return i;
}
// Clear、Indexer setter 同理呼叫 OnChanged
}
class EventListener
{
private ListWithChangedEvent _list;
public EventListener(ListWithChangedEvent list)
{
_list = list;
_list.Changed += ListChanged; // Attach
}
private void ListChanged(object sender, EventArgs e) // Update
{
Console.WriteLine("列表已變更");
}
public void Detach() => _list.Changed -= ListChanged; // Detach
}
event 關鍵字限制外部只能 +=/-=,不能直接 = 覆蓋或 () 呼叫,封裝性更好。EventHandler<TEventArgs>、EventArgs、sender 慣例,工具支援完善。WeakEventManager、WeakReference)。event X { add { } remove { } } 自訂儲存邏輯(如壓縮儲存、轉發)。await event.InvokeAsync(...)(需自行實作或用 AsyncEventHandler 模式)。理解事件與觀察者模式的對應關係,不僅能寫出更地道的 C# 代碼,也能在架構設計中靈活選擇「語言內建事件」或「手動觀察者/中介者/訊息總線」。