委托本質
委托是類型安全的函數指針,封裝了「方法簽名」(參數列表、返回類型)。它是**引用類型**,可以像對象一樣傳遞、存儲、組合。
你已經在用委托了
// WinForms / WPF 事件綁定本質
button.Click += Button_Click; // Button_Click 方法被封裝為 EventHandler 委托實例
// 等價於
button.Click += new EventHandler(Button_Click);
// EventHandler 定義
public delegate void EventHandler(object sender, EventArgs e);
委托演進史
| 版本 | 語法 | 示例 | 特點 |
| C# 1.0 | 命名方法 | `del = new Del(MethodName);` | 需單獨定義方法 |
| C# 2.0 | 匿名方法 | `del = delegate(int x) { return x*2; };` | 內聯代碼、捕獲外部變量 |
| C# 3.0 | Lambda 表達式 | `del = x => x * 2;` | 簡潔、類型推斷、表達式樹 |
| C# 7.0+ | 局部函數 | `int Local(int x) => x*2; del = Local;` | 僅當前方法可見、避免委托分配 |
核心類型:Func / Action / Predicate
// 無返回值,0-16參數
Action act = () => Console.WriteLine("Hi");
Action act2 = (i, s) => Console.WriteLine($"{i}: {s}");
// 有返回值,最後一個類型為返回類型
Func add = (a, b) => a + b;
Func getTime = () => DateTime.Now.ToString();
// 返回 bool,常用於篩選
Predicate isLong = s => s.Length > 10;
多播委托
Action multi = null;
multi += () => Console.WriteLine("First");
multi += () => Console.WriteLine("Second");
multi(); // 依次調用,輸出 First 後 Second
// 移除
multi -= () => Console.WriteLine("First"); // 注意:需保持同一委托實例引用才能移除
進階:事件模式標準實現
public class Timer {
// 1. 定義委托類型(或直接用 EventHandler)
public event EventHandler Elapsed;
// 2. 觸發方法(線程安全模式)
protected virtual void OnElapsed(ElapsedEventArgs e) {
Volatile.Read(ref Elapsed)?.Invoke(this, e);
}
// 3. 內部邏輯觸發
private void Loop() {
while (running) {
Thread.Sleep(interval);
OnElapsed(new ElapsedEventArgs(DateTime.Now));
}
}
}
// 訂閱者
timer.Elapsed += (sender, e) => Console.WriteLine($"Tick at {e.Time}");
學習路徑建議
- 掌握 `Func/Action/Predicate` 常用簽名,減少自定義委托
- 理解**閉包捕獲變量生命週期**(`foreach` 陷阱、異步委托)
- 學習 `async/await` 與委托結合(`Task.Run(() => ...)`)
- 閱讀 .NET Core 源碼中委托實現(`MulticastDelegate`)
- 上一篇文章: C語言字符刪除函數解析:哈希表標記法高效過濾指定字符
- 下一篇文章: MFC UDP通信接收截斷:Unicode項目中char數組導致單字節接收解決方案
Copyright ©
程式碼之家 All Rights Reserved