委托 是 C# 中**類型安全、面向對象的函數指針**。核心特性:
// 1. 聲明委托類型
public delegate void HelloHandler(string msg);
// 2. 目標方法 (簽名匹配)
private void SayHello(string s) => MessageBox.Show(s);
// 3. 實例化並調用
HelloHandler h = new HelloHandler(SayHello);
h("Hello World!"); // 同步調用 SayHello
// 等價簡寫 (C# 2.0+)
HelloHandler h2 = SayHello; // 方法組隱式轉換
h2("Hi");
private void Write1(string s) => Debug.WriteLine("Write1: " + s);
private void Write2(string s) => Debug.WriteLine("Write2: " + s);
HelloHandler h = Write1;
h += Write2; // 串聯
h("Test");
// 輸出:
// Write1: Test
// Write2: Test
面臨「對象 A 需通知對象 B 某事發生」時,問自己四個問題:
// 編輯窗體
public partial class EditForm : Form {
public Action OnSaved; // 委托屬性
private void btnSave_Click(object sender, EventArgs e) {
// ... 保存邏輯 ...
OnSaved?.Invoke(updatedRow); // 觸發回調
this.Close();
}
}
// 主窗體
var form = new EditForm();
form.OnSaved = row => { grid.RefreshRow(row); }; // 註冊
form.ShowDialog();
public interface IRowEditorCallback {
void OnRowSaved(DataRow row);
void OnRowCancelled();
}
public partial class EditForm : Form {
public IRowEditorCallback Callback { get; set; }
// ... 調用 Callback?.OnRowSaved(row) ...
}
// 主窗體實現介面
public class MainForm : Form, IRowEditorCallback {
public void OnRowSaved(DataRow row) => grid.RefreshRow(row);
public void OnRowCancelled() { }
// ... new EditForm { Callback = this } ...
}
// DataRow 為引用類型,修改即影響原對象
var form = new EditForm(existingRow); // 構造函數接收行
form.ShowDialog();
// 無需回調,主窗體直接感知行變更 (若綁定 BindingSource 自動刷新)
| 場景 | 推薦方案 | 理由 |
|---|---|---|
| 單一通知、輕量級、臨時關聯 | 委托 / `Action | 語法輕量、無需定義介面 |
| 多通知點、契約化、需編譯期檢查 | 介面回調 | 語義清晰、支持多方法、利於測試 Mock |
| 共享可變數據對象 (引用類型) | 直接傳遞對象 / 構造函數注入 | 最簡單、零樣板、自動同步 |
| 廣播式、多訂閱者、生命週期獨立 | 事件 (`event` 關鍵字) | 封裝 `+=/-=`、防止外部調用、標準模式 |