Effective C# 3rd 読書メモ 38 LINQではメソッドではなくラムダ式を使う

以下のように、似通った部分のあるコードを見かけると、共通化したくなるのはプログラマーの性だ。

public static void Main()
{
    var allEmployees = FindAllEmployees();

    var earlyFolks = from e in allEmployees
        where e.Classification == EmployeeType.Salaly
        where e.YearsOfService > 20
        where e.MonthlySalary < 4000
        select e;

    var newest = from e in allEmployees
        where e.Classification == EmployeeType.Salaly
        where e.YearsOfService < 2
        where e.MonthlySalary < 4000
        select e;
}

しかし、以下のような判別ロジックの共通化はうまくいかない。

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

public static void Main()
{
    var allEmployees = FindAllEmployees();

    var earlyFolks = from e in allEmployees
        where LowPaidSalaried(e) && e.YearsOfService > 20
        select e;

    var newest = from e in allEmployees
        where LowPaidSalaried(e) && e.YearsOfService < 2
        select e;
}

LINQ to Objectsは、ラムダ式をデリゲートに変換し、コードを実行する。
一方、LINQ to SQLは、ラムダ式から式ツリーを作成し、式を構文解析して、それを別の環境(SQL Server等)で実行する。LINQの式の中にメソッド呼び出しが含まれると例外が発生する。

LINQの式を再利用可能にしたい場合、閉じた型のジェネリックに対する拡張メソッドとして実装するのが最も能率的である。

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

public static void Main()
{
    var allEmployees = FindAllEmployees();
    var salaried = allEmployees.LowPaidSalariedFilter();
    var earlyFolks = salaried.Where(e => e.YearsOfService > 20);
    var newest = salaried.Where(e => e.YearsOfService < 2);
}

コメントを残す

コメントを残す