C# 2.0 引入的匿名方法是委託語法的重大革新,允許在委託實例化處直接編寫方法體,無需單獨定義命名方法。本文通過對比傳統委託與匿名方法,深入解析其語法特性、變量捕獲機制(閉包)及最佳實踐場景。
// 1. 定義委託類型
public delegate bool Predicate(int value);
// 2. 定義匹配簽名的命名方法
private bool IsEven(int number)
{
return number % 2 == 0;
}
// 3. 實例化委託並調用
int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int[] evens = Array.FindAll(numbers, IsEven); // 需額外定義方法
// 直接在委託實例化處編寫邏輯
int[] evens = Array.FindAll(numbers, delegate(int number)
{
return number % 2 == 0;
});
// C# 3.0+ Lambda 進一步簡化(僅作對比)
// int[] evens = Array.FindAll(numbers, n => n % 2 == 0);
delegate (參數列表)
{
// 方法體
return 結果; // 可選
};
// 傳統寫法
btn.Click += new EventHandler(btn_Click);
void btn_Click(object sender, EventArgs e) { MessageBox.Show("Hello"); }
// 匿名方法寫法
btn.Click += delegate { MessageBox.Show("Hello"); };
// 無參數時可省略 delegate()
btn.Click += delegate { /* ... */ };
int factor = 2;
Predicate filter = delegate(int n)
{
return n % factor == 0; // 捕獲 factor
};
factor = 3; // 修改外層變量
Console.WriteLine(filter(6)); // True (6%3==0) - 捕獲的是變量引用,非值拷貝
// 錯誤示範:所有委託捕獲同一個 i 變量
List actions = new List();
for (int i = 0; i < 3; i++)
{
actions.Add(delegate { Console.WriteLine(i); });
}
actions.ForEach(a => a()); // 輸出 3, 3, 3 (非預期 0,1,2)
// 正確做法:引入局部副本
for (int i = 0; i < 3; i++)
{
int captured = i; // 每次迭代創建新變量
actions.Add(delegate { Console.WriteLine(captured); });
}
actions.ForEach(a => a()); // 輸出 0, 1, 2
| 特性 | 匿名方法 (C# 2.0) | Lambda 表達式 (C# 3.0+) |
|---|---|---|
| 語法簡潔度 | 冗長 | 極簡 (=>) |
| 表達式樹支持 | 不支持 | 支持 (Expression<TDelegate>) |
| 參數類型推斷 | 部分支持 | 完全支持 |
| ref/out 參數 | 支持 | 不支持 |
| 適用場景 | 需 ref/out、維護 .NET 2.0 項目 | 現代開發首選 |
string userName = "Admin";
ThreadPool.QueueUserWorkItem(delegate
{
// 捕獲 userName
LogLogin(userName);
});
List people = GetPeople();
people.Sort(delegate(Person p1, Person p2)
{
return p1.Age.CompareTo(p2.Age); // 年齡排序
});
public void ProcessData(Action onComplete)
{
// 異步處理...
ThreadPool.QueueUserWorkItem(delegate
{
DoWork();
onComplete?.Invoke(); // 執行回調
});
}
// 調用
ProcessData(delegate { UpdateUI(); });
匿名方法是 C# 向函數式編程邁進的關鍵一步,其核心價值在於:
現代 C# 開發中,Lambda 表達式(=>)已全面取代匿名方法,但在維護 .NET Framework 2.0/3.0 老項目、需要 ref/out 參數、或為理解閉包本質時,掌握匿名方法仍有重要價值。