C# 3.0 引入的 LINQ 不僅帶來了查詢語法,更通過 Lambda 表達式與擴展方法徹底改變了集合操作方式。本文通過一個員工篩選場景,演示如何從傳統委托一步步演進到優雅的鏈式查詢。
假設我們需要篩選「工齡超過 3 年」和「屬於銷售部」的員工。早期寫法可能定義委托並編寫通用篩選邏輯:
delegate bool Choose(Employee employee);
static IEnumerable<Employee> Filter(IEnumerable<Employee> employees, Choose choose)
{
foreach (var emp in employees)
if (choose(emp)) yield return emp;
}
// 具體篩選條件
static IEnumerable<Employee> GoldWatch(IEnumerable<Employee> employees)
{
return Filter(employees, emp => emp.Years > 3);
}
static IEnumerable<Employee> SalesForce(IEnumerable<Employee> employees)
{
return Filter(employees, emp => emp.Department == "Sales");
}
雖然可行,但調用方式 GoldWatch(employees) 違背了物件導向的 noun.Verb() 直覺習慣,我們更希望寫成 employees.GoldWatch()。
C# 3.0 的擴展方法完美解決此問題。在靜態類中為 IEnumerable<Employee> 添加實例風格方法:
static IEnumerable<Employee> Filter(this IEnumerable<Employee> employees, Choose choose) { ... }
static IEnumerable<Employee> GoldWatch(this IEnumerable<Employee> employees)
{
return employees.Filter(emp => emp.Years > 3);
}
static IEnumerable<Employee> SalesForce(this IEnumerable<Employee> employees)
{
return employees.Filter(emp => emp.Department == "Sales");
}
如今調用變為 employees.GoldWatch(),語義清晰且符合封裝直覺。
若要篩選 Customer、Product 等任意類型,為每個類型編寫 Filter 顯然不可取。泛型委托與泛型方法將其通用化:
delegate bool Choose<T>(T item);
static IEnumerable<T> Filter<T>(this IEnumerable<T> items, Choose<T> choose)
{
foreach (var item in items)
if (choose(item)) yield return item;
}
// 現在可以篩選任何類型!
int[] numbers = { 1, 2, 3, 4, 5 };
var result = numbers.Filter(i => i == 1 || i == 3); // 結果:1, 3
這種模式極其通用,.NET 基礎類庫在 System.Linq.Enumerable 中內建了 Where 擴展方法,簽名如下:
public static IEnumerable<T> Where<T>(
this IEnumerable<T> source,
Func<T, bool> predicate)
{
foreach (T element in source)
if (predicate(element)) yield return element;
}
Func<T, bool> 替代自定義委托,標準化函數簽名。i => i > 10,構成現代 C# 集合操作的基石。從匿名委托 → 擴展方法 → 泛型化 → 框架標準化,LINQ Lambda 表達式配合擴展方法,讓集合查詢從「工具函數調用」昇華為「領域語言風格」,極大提升了代碼可讀性與復用性。