C# での LINQ クエリの作成

この記事では、C# で LINQ クエリを作成できる 3 つの方法を示しています。

  1. クエリ構文を使用する。

  2. メソッド構文を使用する。

  3. クエリ構文とメソッド構文を組み合わせて使用する。

以下の例では、上記の各アプローチを使用したシンプルな LINQ クエリを示します。 一般に、可能であれば常に (1) を使用し、(2) と (3) は必要に応じて使用するというのがルールになっています。

注意

これらのクエリでは、シンプルなメモリ内コレクションに対して操作を実行します。ただし、基本的な構文は、LINQ to Entities および LINQ to XML で使用されるのと同じものです。

例 - クエリ構文

ほとんどのクエリ記述については、クエリの構文を使用してクエリ式を作成することをお勧めします。 次の例は、3 つのクエリ式を示しています。 1 つ目のクエリ式は、where 句を使用した条件を適用することで、結果をフィルター処理または制限する方法を示しています。 このクエリは、値が 7 より大きいか、または 3 より小さいソース シーケンス内のすべての要素を返します。 2 つ目の式は、返された結果を並べ替える方法を示しています。 3 つ目の式は、キーに基づいて結果をグループ化する方法を示しています。 このクエリは、単語の頭文字に基づいて 2 つのグループを返します。

List<int> numbers = new() { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

// The query variables can also be implicitly typed by using var

// Query #1.
IEnumerable<int> filteringQuery =
    from num in numbers
    where num < 3 || num > 7
    select num;

// Query #2.
IEnumerable<int> orderingQuery =
    from num in numbers
    where num < 3 || num > 7
    orderby num ascending
    select num;

// Query #3.
string[] groupingQuery = { "carrots", "cabbage", "broccoli", "beans", "barley" };
IEnumerable<IGrouping<char, string>> queryFoodGroups =
    from item in groupingQuery
    group item by item[0];

クエリの型が IEnumerable<T> であることに注意してください。 これらのクエリはすべて、次の例で示すように、var を使用しても記述できます。

var query = from num in numbers...

上記の各例では、foreach ステートメントまたはその他のステートメントでクエリ変数を反復処理するまで、クエリは実際には実行されません。 詳しくは、「LINQ クエリの概要」をご覧ください。

例 - メソッド構文

一部のクエリ操作は、メソッド呼び出しとして表す必要があります。 このようなメソッドで最も一般的なものは、SumMaxMinAverage のような単一の数値を返すメソッドです。 これらのメソッドは、単一の値のみを表し、追加のクエリ操作のソースとしては使用できないため、常に、どのクエリよりも後に呼び出す必要があります。 次の例は、クエリ式でのメソッド呼び出しを示したものです。

List<int> numbers1 = new() { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
List<int> numbers2 = new() { 15, 14, 11, 13, 19, 18, 16, 17, 12, 10 };

// Query #4.
double average = numbers1.Average();

// Query #5.
IEnumerable<int> concatenationQuery = numbers1.Concat(numbers2);

メソッドに Action または Func パラメーターがある場合、それらはラムダ式の形式で提供されます。次に例を示します。

// Query #6.
IEnumerable<int> largeNumbersQuery = numbers2.Where(c => c > 15);

上記のクエリでは Query #4 だけが直ちに実行されます。 これは、それがジェネリック IEnumerable<T> コレクションではなく、単一値を返すためです。 メソッド自体は、値を計算するために foreach を使用する必要があります。

上記の各クエリは、var による暗黙的型指定を使用しても記述できます。次に例を示します。

// var is used for convenience in these queries
var average = numbers1.Average();
var concatenationQuery = numbers1.Concat(numbers2);
var largeNumbersQuery = numbers2.Where(c => c > 15);

例 - クエリとメソッド構文の併用

この例では、クエリ句の結果に対してメソッド構文を使用する方法を示します。 方法は、クエリ式をかっこで囲み、ドット演算子を適用して、メソッドを呼び出すだけです。 次の例では、Query #7 は、値が 3 ~ 7 である数値のカウントを返します。 ただし一般的には、メソッド呼び出しの結果の格納には、2 番目の変数を使うほうが賢明です。 この方法のほうが、クエリをクエリ結果と混同する恐れがありません。

// Query #7.

// Using a query expression with method syntax
int numCount1 = (
    from num in numbers1
    where num < 3 || num > 7
    select num
).Count();

// Better: Create a new variable to store
// the method call result
IEnumerable<int> numbersQuery =
    from num in numbers1
    where num < 3 || num > 7
    select num;

int numCount2 = numbersQuery.Count();

Query #7 はコレクションではなく単一の値を返すので、クエリはすぐに実行されます。

上記のクエリは、var による暗黙的型指定を使用しても記述できます。次に例を示します。

var numCount = (from num in numbers...

次のように、メソッド構文で記述することもできます。

var numCount = numbers.Where(n => n < 3 || n > 7).Count();

次のように、明示的な型指定を使用して記述することもできます。

int numCount = numbers.Where(n => n < 3 || n > 7).Count();

こちらもご覧ください