委派是 C# 型別安全的函式指標,支援多點廣播、實例/靜態方法綁定。C# 2.0 引入匿名委派進一步簡化語法,並透過閉包機制捕獲外部變數,極大增強表達能力。本文對比傳統與匿名委派語法,並展示非同步呼叫、上下文捕獲等進階應用場景。
C# 1.x 傳統寫法:
public delegate void TheEvent(int a);
public void Test()
{
TheEvent testdel1 = new TheEvent(Del1); // 顯式建構
testdel1(12);
}
public void Del1(int x) { Console.WriteLine("output x: {0}", x); }
C# 2.0 簡化語法(方法群組轉換):
TheEvent testdel1 = Del1; // 隱式轉換
testdel1(12);
delegate void TheEvent2(int a);
public void Test2()
{
int a = 12;
TheEvent2 ev2 = delegate(int x) { Console.WriteLine("output x: {0}", x); };
ev2(a);
}
更強大之處在於捕獲外部區域變數:
public static void Test3()
{
int a = 12;
int y = 32; // 外部區域變數
TheEvent ev2 = delegate(ref int x)
{
Console.WriteLine("output x + y: {0}", x + y); // 直接存取 y
};
ev2(ref a); // 輸出 44
}
傳統委派無法存取參數以外的區域變數,匿名委派透過閉包機制打破此限制。
結合 BeginInvoke/EndInvoke 實作非同步模式,匿名委派自動捕獲呼叫端上下文:
public static void Test4()
{
int a = 12;
int y = 32;
TheEvent ev2 = delegate(ref int x)
{
Console.WriteLine("output x + y: {0}", x + y);
Thread.Sleep(100); // 模擬耗時運算
};
// 非同步啟動
IAsyncResult ar = ev2.BeginInvoke(ref a,
delegate(IAsyncResult ar2) // 完成回呼也是匿名委派
{
Console.WriteLine("完成: 執行緒 {0}, 集區執行緒 {1}",
Thread.CurrentThread.GetHashCode(), Thread.CurrentThread.IsThreadPoolThread);
},
null);
Console.WriteLine("主執行緒繼續執行其他運算...");
Console.WriteLine("狀態: {0}, 主執行緒 {1}, 集區 {2}",
ar.IsCompleted, Thread.CurrentThread.GetHashCode(), Thread.CurrentThread.IsThreadPoolThread);
Thread.Sleep(500); // 等待完成
ev2.EndInvoke(ref a, ar);
}
輸出顯示工作項目被排入執行緒集區執行,主執行緒可繼續處理其他邏輯。匿名委派完整複製當時可用的區域變數(a、y),使回呼邏輯自然存取上下文資料。
C# 2.0 匿名委派不僅是語法糖,其閉包特性實現了區域變數捕獲,配合非同步模式可編寫極具表達力的並行程式碼。理解其編譯器實作(巢狀類別閉包)與變數捕獲語意,是避免陷阱、發揮最大效用的關鍵。