以下のように、似通った部分のあるコードを見かけると、共通化したくなるのはプログラマーの性だ。
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);
}