C# の LINQ クエリ構文とメソッド構文

LINQ には2つの書き方がある。クエリ構文とメソッド構文だ。どちらも同じ結果を得られるが、見た目と使い勝手が異なる。

クエリ構文

SQL に似た書き方で、宣言的にクエリを記述する。

int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

var query = from n in numbers
            where n % 2 == 0
            orderby n descending
            select n;

foreach (var n in query)
{
    Console.WriteLine(n);  // 10, 8, 6, 4, 2
}

fromwhereorderbyselect といったキーワードを使う。SQL を知っている人には馴染みやすい構文である。

メソッド構文

拡張メソッドをチェーンして記述する。ラムダ式と組み合わせて使う。

int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

var query = numbers
    .Where(n => n % 2 == 0)
    .OrderByDescending(n => n);

foreach (var n in query)
{
    Console.WriteLine(n);  // 10, 8, 6, 4, 2
}

メソッドをドットで繋げていく。各メソッドが何をしているか、コードから直接読み取れる。

両者の比較

クエリ構文

SQL ライクで直感的。複雑な結合やグループ化が読みやすい。ただし使えるメソッドに制限がある。

メソッド構文

すべての LINQ メソッドが使える。短いクエリでは簡潔に書ける。慣れると可読性も高い。

実際のところ、クエリ構文はコンパイル時にメソッド構文に変換される。つまり両者は等価であり、好みや状況に応じて使い分ければよい。

クエリ構文でできないこと

一部の LINQ メソッドはクエリ構文では直接呼び出せない。

int[] numbers = { 1, 2, 3, 4, 5 };

// メソッド構文でしか使えない例
int count = numbers.Count();
int sum = numbers.Sum();
int first = numbers.First();
bool any = numbers.Any(n => n > 3);

CountSumFirstAny などの集計・判定メソッドはメソッド構文で呼び出す必要がある。クエリ構文と組み合わせる場合は、クエリを括弧で囲んでからメソッドを呼ぶ。

int[] numbers = { 1, 2, 3, 4, 5 };

int count = (from n in numbers
             where n > 2
             select n).Count();

Console.WriteLine(count);  // 3

どちらを使うべきか

現場ではメソッド構文が主流だ。理由はいくつかある。

すべての LINQ メソッドが使える
短いクエリでは記述量が少ない
メソッドチェーンは C# の他の機能とも相性がいい

ただし、複数のデータソースを結合するような複雑なクエリでは、クエリ構文の方が読みやすいこともある。両方の書き方を理解しておき、状況に応じて選択するのが理想的だ。