委托適用於其他語言需用函數指針解決的場景,但委托是面向對象且類型安全的。它是 C# 事件模型、回調、異步編程、LINQ 查詢的基石。本文對應規范第 1.10 節「委托」。
委托實例不知道也不關心封裝方法所屬的類型、訪問性、靜態與否,只關心簽名兼容性。這使委托極適合「匿名調用」—— 強大的解耦能力。
delegate void SimpleDelegate(); // 無參、無返回值
class Test
{
static void F() => Console.WriteLine("Test.F");
static void Main()
{
// 創建委托實例綁定靜態方法
SimpleDelegate d = new SimpleDelegate(F);
// 或簡寫 (C# 2.0+ 方法組轉換)
SimpleDelegate d2 = F;
// 3. 調用
d(); // 輸出 "Test.F"
}
}
// 不關心具體方法,只關心簽名兼容
void MultiCall(SimpleDelegate d, int count)
{
for (int i = 0; i < count; i++)
d();
}
// 使用
MultiCall(F, 3); // 執行 3 次 F
MultiCall(() => Console.WriteLine("Lambda!"), 2); // 匿名方法/Lambda
| 特性 | C/C++ 函數指針 | C# 委托 |
|---|---|---|
| 類型安全 | 無 (僅簽名匹配,易崩潰) | 編譯期強檢查 |
| 面向對象 | 否 | 是 (繼承 Delegate/MulticastDelegate) |
| 綁定目標 | 僅函數地址 | 實例+方法 / 靜態方法 |
| 多播 | 不支持 | 內建支持 (+=/-= 組合調用列表) |
| 捕獲上下文 | 需手動傳遞上下文指針 | 閉包/匿名方法自動捕獲 |
| 垃圾回收 | 手動管理 | 托管,自動生命週期 |
SimpleDelegate d = F;
d += G; // 組合
d += () => Console.WriteLine("Lambda");
d(); // 依次調用 F, G, Lambda
d -= G; // 移除
// 調用列表順序 = 添加順序,異常會中斷後續調用
C# 3.0+ 引入預定義泛型委托,絕大多數場景無需自定義 `delegate`:
// 無返回:Action, Action, Action...
Action log = () => Console.WriteLine("Log");
Action logMsg = msg => Console.WriteLine(msg);
// 有返回:Func, Func...
Func add = (a, b) => a + b;
Func getTime = () => DateTime.Now.ToString();
// 異步/任務
Func asyncOp = async () => await DoWork();
委托是 C# 類型系統中「可執行代碼」的一等公民表示。它以類型安全、面向對象、多播、閉包捕獲特性,完美替代了函數指針,並構成了事件、異步、LINQ、函數式編程的基礎設施。理解「聲明定義類、實例封裝調用列表、調用遍歷列表」的核心模型,是掌握 C# 高級編程的關鍵。