在 C# 開發中,Lambda 表達式雖然簡潔,但若直接內聯在 LINQ 查詢中,相同的過濾邏輯往往會在多處重複出現。例如要篩選「月薪 4000 以下且職等為 1 的資深員工」,若在多個查詢中都寫 e.MonthlySalary < 4000 && e.Classification == 1 && e.YearsOfService > 20,不僅違反 DRY 原則,還增加維護成本。
直覺上會將條件提煉為私有靜態方法:
private static bool LowPaidSalaried(Employee e, int salary) {
return e.MonthlySalary < salary && e.Classification == 1;
}
然後在查詢中呼叫 where LowPaidSalaried(e, 4000) && e.YearsOfService > 20。然而,這在 LINQ to SQL 或 Entity Framework 中會導致執行時期錯誤,因為提供者無法將自訂方法轉譯為 SQL。編譯器雖通過,但運行時拋出異常,反而降低了可復用性。
LINQ 的延遲執行特性意味著查詢變數保存的是「獲取資料的步驟」,而非資料本身。利用這一點,我們可以將 Lambda 邏輯封裝為 IQueryable<T> 的擴展方法,疊加查詢步驟:
public static IQueryable<Employee> LowPaidSalaried(this IQueryable<Employee> sequence) {
return from s in sequence
where s.Classification == 1 && s.MonthlySalary < 4000
select s;
}
使用時:var salaried = allEmployees.LowPaidSalaried(); 只有在真正枚舉(如 ToList()、foreach)時才會觸發執行,且對 LINQ to SQL/EF 友好,能正確轉譯為 SQL。
若資料源為 IEnumerable<T>(記憶體內集合),可使用 yield return 實現相同的延遲流水線:
public static IEnumerable<Employee> LowPaidSalaried(this IEnumerable<Employee> source) {
foreach (var e in source)
if (e.Classification == 1 && e.MonthlySalary < 4000)
yield return e;
}
IQueryable<T> 擴展方法,保留提供者轉譯能力。WhereLowPaid),語意清晰。Expression<Func<T, bool>> 組合。掌握這些技巧,能讓 Lambda 表達式在複雜查詢中既保持簡潔,又兼顧效能與跨提供者相容性。