在 C# 中,委派與事件是實作「觀察者模式」的核心機制。委派封裝方法,事件則標準化委派的發布/訂閱模型,讓物件之間保持鬆散耦合。本文將從委派基礎、事件語法、到完整觀察者模式範例,逐步深入解析。
委派定義一種型別,封裝具有特定參數與回傳值的方法:
public delegate void PrintHandler(string str);
此宣告定義了 PrintHandler 型別,可指向任何回傳 void、接受單一 string 參數的方法。
PrintHandler handler = new PrintHandler(MyPrintMethod);
// 或簡寫
PrintHandler handler = MyPrintMethod;
if (handler != null)
handler("Hello World");
委派可串聯多個方法,使用 +=、-= 或 Delegate.Combine/Remove:
handler += AnotherMethod;
handler -= MyPrintMethod;
呼叫時會依序執行鏈結串列中的所有方法。
事件本質是特殊的多播委派,.NET 規範要求事件委派簽名必須符合:
object sender(事件來源)、EventArgs e(事件資料)e 型別必須為 EventArgs 或其衍生類別public delegate void CustomEventHandler(object sender, EventArgs e);
public event CustomEventHandler OnCustomEvent;
僅能在宣告事件的類別內部引發,習慣先檢查 null:
protected virtual void RaiseEvent(EventArgs e)
{
if (OnCustomEvent != null)
OnCustomEvent(this, e);
}
外部物件透過 +=/-= 註冊處理方法:
publisher.OnCustomEvent += HandlerMethod;
publisher.OnCustomEvent -= HandlerMethod;
若 Employee 直接參考 Manager 並呼叫其方法,會導致:
步驟 1:定義事件委派與事件引數
public delegate void PlayGameHandler(object sender, EventArgs e);
public class PlayGameEventArgs : EventArgs
{
public string EmployeeName { get; set; }
}
步驟 2:發布者 - Employee 類別
public class Employee
{
public event PlayGameHandler PlayGame;
public string Name { get; set; }
public int Salary { get; set; } = 1000;
public void Play()
{
Console.WriteLine($"{Name} 開始玩遊戲...");
OnPlayGame(new PlayGameEventArgs { EmployeeName = Name });
}
protected virtual void OnPlayGame(PlayGameEventArgs e)
{
PlayGame?.Invoke(this, e);
}
}
步驟 3:訂閱者 - Manager 類別
public class Manager
{
public void DeductSalary(object sender, PlayGameEventArgs e)
{
var emp = sender as Employee;
if (emp != null)
{
Console.WriteLine($"主管發現 {emp.Name} 玩遊戲,扣薪 500 元");
emp.Salary -= 500;
}
}
}
步驟 4:客戶端程式碼組裝
var emp = new Employee { Name = "小張" };
var mgr = new Manager();
// 訂閱事件
emp.PlayGame += mgr.DeductSalary;
Console.WriteLine($"原薪資:{emp.Salary}");
emp.Play();
Console.WriteLine($"現薪資:{emp.Salary}");
SecurityGuard 實例,Employee 完全不需修改。mgr.DeductSalary 與 hr.DeductPerformance,單一事件觸發多個回應。按鈕點擊事件即是典型觀察者模式:
this.button1.Click += new EventHandler(this.Button1_Click);
private void Button1_Click(object sender, EventArgs e)
{
// 處理邏輯
}
委派與事件讓 C# 能以極少代碼實作觀察者模式,核心三要素:
善用此機制,可大幅降低類別間耦合,提升系統擴充性與維護性。