初學 C# 時,「委派」常被比喻為「C++ 函數指標」,對沒學過 C++ 的開發者而言無異天書。其實委派本質是一個「型別安全的函數參考」,它讓方法能像變數一樣被傳遞、儲存、呼叫。事件則是委派的受控封裝,實現「發布-訂閱」模式。本文用一個買菜的生活化例子,帶你輕鬆理解委派與事件的運作機制。
白菜規則固定,直接寫死在方法裡;馬鈴薯規則不確定,必須在執行時才能決定,這就是委派的用武之地。
/// 買馬鈴薯的委派:輸入單價與數量,回傳總價
public delegate double BuyPotatoDelegate(double price, double amount);
public class VegetableBuyer
{
double _cabbageTotal, _potatoTotal;
// 白菜:固定規則
public void BuyCabbage(double price, double amount)
{
_cabbageTotal = price < 3 ? price * amount : (price - 0.3) * amount;
}
// 馬鈴薯:宣告事件,型別為委派
public event BuyPotatoDelegate PotatoPurchased;
public void BuyPotato(double price, double amount)
{
// 呼叫事件(若有訂閱者),取得計算結果
_potatoTotal = PotatoPurchased?.Invoke(price, amount) ?? 0;
}
public double GetTotal() => _cabbageTotal + _potatoTotal;
}
protected void Page_Load(object sender, EventArgs e)
{
var buyer = new VegetableBuyer();
// 白菜直接買
buyer.BuyCabbage(3.6, 8);
// 馬鈴薯:先掛上自訂規則
buyer.PotatoPurchased += PotatoRule;
// 再買馬鈴薯
buyer.BuyPotato(4.8, 9);
Response.Write(buyer.GetTotal());
}
// 具體規則:價格 > 2.5 扣雜質
double PotatoRule(double price, double amount)
{
return price > 2.5 ? (price - 0.3) * amount : price * amount;
}
| 概念 | 說明 | 例子對應 |
|---|---|---|
| 委派型別 | 定義方法簽章的「合約」 | BuyPotatoDelegate |
| 委派實例 | 指向具體方法的「變數」 | PotatoRule 方法 |
| 事件 | 委派的「受控容器」,只能 += / -=,不能直接呼叫 | PotatoPurchased |
| 發布者 | 擁有事件的類別,決定何時觸發 | VegetableBuyer |
| 訂閱者 | 提供具體邏輯,註冊到事件 | Page_Load 中的 += PotatoRule |
委派比介面更輕量:無需定義完整類別、實作多個方法,單一行為即可封裝。事件更進一步限制外部只能訂閱/取消訂閱,不能任意呼叫或清空委派鏈結,保護封裝性。
委派是「方法的參考型別」,事件是「委派的受控公開介面」。透過「買馬鈴薯規則由采購員現場決定」的例子,我們看到:固定邏輯寫死,變動邏輯委派,這正是委派/事件模式的核心價值——將「什麼時候做」與「怎麼做」分離,實現靈活的行為擴充。