Chapter 4 - Item 38 : Lambda Expressions to Methods

Effective C# (Covers C# 6.0), (includes Content Update Program): 50 Specific Ways to Improve Your C#, 3rd Edition By Bill Wagner 讀後心得

作者建議盡量使用 query 方式訪問查詢而非 method calls,但其實這部份見仁見智;本質上兩者轉譯後的語法是相同的(query 轉譯成 method calls)。以下提出一個在實務上容易發生的錯誤。

在 query 寫法中,不要串接自定義的方法;否則會造成執行錯誤(訪問資料庫時)。

範例:

var allEmployees = FindAllEmployees( );

// Find the first employees :
var earlyFolks = from e in allEmployees
                 where e.Classification == EmployeeType.Salary
                 where e.YearOfService > 20
                 where e.MonthlySalary < 4000
                 select e;

// Find the newest people :
var newest = from e in allEmployees
             where e.Classification == EmployeeType.Salary
             where e.YearOfService < 20
             where e.MonthlySalary < 4000
             select e;

這兩段查詢,可以很快發現兩者重覆的部分;依照 don't repeat yourself 原則,很自然的將重覆的查詢抽取出來寫成方法。

private bool LowPaidSalaried( Employee e ) =>
    e.MonthlySalary < 4000 &&
    e.Classification == EmployeeType.Salary;

var allEmployees = FindAllEmployees( );

// Factor out method :
var earlyFolks = from e in allEmployees
                 where LowPaidSalaried( e ) &&
                 e.YearOfService > 20
                 select e;

// Find the newest people :
var newest = from e in allEmployees
             where LowPaidSalaried( e ) &&
             e.YearOfService < 20
             select e;

這樣的寫法在查詢皆在本機記憶體時可以正常運作,但若是需連結資料庫並回傳時就會出現 runtime error。原因在於編譯器會將 query 轉譯成 SQL 查詢語法,並在資料庫端執行;而包裝成方法的寫法會造成轉譯失敗。

比較好的實作方式,是將重覆的部分利用擴充方法提取出來;利用 IQueryable query 可組合的特性,讓客戶端自行串接之後的查詢邏輯一併在資料庫執行。

public static IQueryable<Employee> LowPaidSalariedFilter(
    this IQueryable<Employee> sequence ) =>
    from s in sequence
    where s.Classification == EmployeeType.Salary &&
    s.MonthlySalary < 4000
    select s;

var allEmployees = FindAllEmployees( );

// Find the first employees :
var salaried = allEmployees.LowPaidSalariedFilter( );

var earlyFolks = from e in salaried
                 where e.YearOfService > 20
                 select e;

var newest = from e in salaried
             where e.YearOfService < 20
             select e;
結論:
1. query 與 method calls 本質上相同,使用時機端看開發者習慣。 

2. 串接 query 或 method calls 時,不要在串接時呼叫自定義方法;此舉會造成轉換成 SQL 語法失敗。