C# 2.0 引入匿名方法,消除「為了委派必須寫具名函式」的樣板碼。編譯器自動生成隱藏類別封裝捕獲變數,實現閉包語義,運行期效能與具名函式幾乎相同,生產力大幅提升。
delegate void Action();
// 匿名方法賦值給委派
Action a = delegate { Console.WriteLine("Hello"); };
a();
// 帶參數
delegate void ActionT(string msg);
ActionT b = delegate(string m) { Console.WriteLine(m); };
b("World");
匿名方法可存取定義範圍外的區域變數(外部變數),編譯器將其「提升」為隱藏類別的欄位:
void Demo() {
string name = "Zach"; // 外部變數
Action a = delegate { Console.WriteLine(name); };
a(); // 輸出 Zach
name = "Smith"; // 修改外部變數
a(); // 輸出 Smith - 捕獲的是變數本身,非值快照!
}
ref/out 參數不能被捕獲
// 來源
int i = 0;
Action a = delegate { i++; };
// 編譯器產生 (簡化)
class __DisplayClass {
public int i;
public void __Anonymous() => this.i++;
}
// 使用
var ctx = new __DisplayClass { i = 0 };
Action a = ctx.__Anonymous;
Action a = delegate { Console.WriteLine("1"); };
a += delegate { Console.WriteLine("2"); }; // 疊加
a(); // 輸出 1 然後 2
a -= delegate { Console.WriteLine("1"); }; // 移除需相同委派實例,通常保存引用
void Execute(Action a) => a();
Execute(delegate { Console.WriteLine("Inline"); });
class Demo {
int _counter = 0;
void Run() {
Action a = delegate { Console.WriteLine(_counter++); };
a(); // 0
a(); // 1 - 捕獲 this,存取實例欄位
}
}
for(int i=0;i<10;i++) actions.Add(delegate{Console.Write(i);}); → 全輸出 10。修正:int j=i; actions.Add(delegate{Console.Write(j);});del = null 釋放ref/out 不可捕獲,需用區域變數中轉匿名方法是 C# 邁向函數式程式設計的關鍵一步,掌握其捕獲語義與編譯器實現,能寫出更簡潔、更具表達力的代碼。