標準クエリ演算子は、LINQ パターンを形成するキーワードとメソッドです。 C# 言語では、最も一般的なクエリ式に使用する LINQ クエリ キーワード を定義します。 コンパイラは、これらのキーワードを使用して式を同等のメソッド呼び出しに変換します。 2 つの形式は同義です。 System.Linq名前空間の一部である他のメソッドには、同等のクエリ キーワードがありません。 このような場合は、メソッド構文を使用する必要があります。 このセクションでは、すべてのクエリ演算子キーワードについて説明します。 ランタイムやその他の NuGet パッケージでは、各リリースで LINQ クエリを操作するように設計されたメソッドがさらに追加されます。 クエリ キーワードに相当するものを含む最も一般的な方法については、このセクションで説明します。 .NET ランタイムでサポートされているクエリ メソッドの完全な一覧については、 System.Linq.Enumerable API のドキュメントを参照してください。 このクラスには、ここで説明するメソッドに加えて、データ ソースを連結し、合計、平均、その他の値など、データ ソースから 1 つの値を計算するためのメソッドが含まれています。
Von Bedeutung
これらのサンプルでは、System.Collections.Generic.IEnumerable<T> データ ソースを使用します。
System.Linq.IQueryProvider に基づくデータ ソースでは、System.Linq.IQueryable<T> データ ソースと式ツリーが使用されます。 式ツリーには、許可される C# 構文に制限があります。 さらに、IQueryProvider
などの各 データ ソースでは、より多くの制限が課される場合があります。 ご利用のデータ ソースのドキュメントをご覧ください。
これらのメソッドのほとんどはシーケンスで動作します。シーケンスは、 IEnumerable<T> インターフェイスまたは IQueryable<T> インターフェイスを実装する型のオブジェクトです。 標準のクエリ演算子は、フィルター処理、プロジェクション、集計、並べ替えなどのクエリ機能を提供します。 各セットを構成するメソッドは、それぞれ Enumerable クラスと Queryable クラスの静的メンバーです。 これらは、操作する型の 拡張メソッド として定義されます。
IEnumerable<T>シーケンスとIQueryable<T> シーケンスの違いによって、実行時のクエリの実行方法が決まります。
IEnumerable<T>
の場合、返される列挙可能なオブジェクトは、メソッドに渡された引数をキャプチャします。 そのオブジェクトが列挙されると、クエリ演算子のロジックが使用され、クエリ結果が返されます。
IQueryable<T>
の場合、クエリは式ツリーに変換されます。 データ ソースがクエリを最適化できる場合は、式ツリーをネイティブ クエリに変換できます。
Entity Framework などのライブラリは、LINQ クエリを、データベースで実行されるネイティブ SQL クエリに変換します。
次のコード例は、標準のクエリ演算子を使用してシーケンスに関する情報を取得する方法を示しています。
string sentence = "the quick brown fox jumps over the lazy dog";
// Split the string into individual words to create a collection.
string[] words = sentence.Split(' ');
// Using query expression syntax.
var query = from word in words
group word.ToUpper() by word.Length into gr
orderby gr.Key
select new { Length = gr.Key, Words = gr };
// Using method-based query syntax.
var query2 = words.
GroupBy(w => w.Length, w => w.ToUpper()).
Select(g => new { Length = g.Key, Words = g }).
OrderBy(o => o.Length);
foreach (var obj in query)
{
Console.WriteLine($"Words of length {obj.Length}:");
foreach (string word in obj.Words)
Console.WriteLine(word);
}
// This code example produces the following output:
//
// Words of length 3:
// THE
// FOX
// THE
// DOG
// Words of length 4:
// OVER
// LAZY
// Words of length 5:
// QUICK
// BROWN
// JUMPS
可能であれば、このセクションのクエリでは、入力ソースとして一連の単語または数字が使用されます。 オブジェクト間のより複雑なリレーションシップが使用されるクエリでは、学校をモデル化する次のソースが使用されます。
public enum GradeLevel
{
FirstYear = 1,
SecondYear,
ThirdYear,
FourthYear
};
public class Student
{
public required string FirstName { get; init; }
public required string LastName { get; init; }
public required int ID { get; init; }
public required GradeLevel Year { get; init; }
public required List<int> Scores { get; init; }
public required int DepartmentID { get; init; }
}
public class Teacher
{
public required string First { get; init; }
public required string Last { get; init; }
public required int ID { get; init; }
public required string City { get; init; }
}
public class Department
{
public required string Name { get; init; }
public int ID { get; init; }
public required int TeacherID { get; init; }
}
各 Student
は、学年、主要学科、一連のスコアを持っています。
Teacher
は、その教師が授業を受け持つキャンパスを示す City
プロパティも持っています。
Department
は名称と、学科長を務める Teacher
への参照を持っています。
ソース リポジトリでデータ セットを見つけることができます。
クエリ演算子の種類
標準クエリ演算子は、シングルトン値と値のシーケンスのどちらを返すかによって、実行のタイミングが異なります。 シングルトン値を返すメソッド ( Average や Sumなど) は直ちに実行されます。 シーケンスを返すメソッドは、クエリの実行を延期し、列挙可能なオブジェクトを返します。 1 つのクエリの出力シーケンスを、別のクエリへの入力シーケンスとして使用できます。 クエリ メソッドの呼び出しは、1 つのクエリで連結できるため、クエリが任意に複雑になります。
クエリ演算子
LINQ クエリでは、最初の手順としてデータ ソースを指定します。 LINQ クエリでは、データ ソース (from
) とstudents
() を導入するために、student
句が最初に使用されます。
//queryAllStudents is an IEnumerable<Student>
var queryAllStudents = from student in students
select student;
範囲変数は、クエリ式で実際のイテレーションが発生しない点を除き、 foreach
ループ内の反復変数に似ています。 クエリが実行されると、範囲変数は、 students
内の連続する各要素への参照として機能します。 コンパイラは student
の型を推論できるため、明示的に指定する必要はありません。
let
句では、より多くの範囲変数を導入できます。 詳細については、「let 句」を参照してください。
注
ArrayListなどの非ジェネリック データ ソースの場合は、範囲変数を明示的に型指定する必要があります。 詳細については、「LINQ (C#) を使用して ArrayList にクエリを実行する方法」および「from 句」を参照してください。
データ ソースを取得したら、そのデータ ソースに対して任意の数の操作を実行できます。
-
キーワードを使用して
where
します。 -
と必要に応じて
orderby
キーワードを使用してdescending
えます。 -
を使用して
group
化し、必要に応じてキーワードをinto
します。 -
キーワードを使用して
join
します。 -
プロジェクト データは
select
キーワードを使用します。
クエリ式の構文表
次の表に、同等のクエリ式句を持つ標準クエリ演算子を示します。
LINQ を使用したデータ変換
Language-Integrated クエリ (LINQ) は、データの取得だけではありません。 また、データを変換するための強力なツールでもあります。 LINQ クエリを使用すると、ソース シーケンスを入力として使用し、さまざまな方法で変更して新しい出力シーケンスを作成できます。 並べ替えやグループ化によって要素自体を変更することなく、シーケンス自体を変更できます。 しかし、おそらく LINQ クエリの最も強力な機能は、新しい型を作成する機能です。 select 句は、入力要素から出力要素を作成します。 これを使用して、入力要素を出力要素に変換します。
- 複数の入力シーケンスを、新しい型を持つ 1 つの出力シーケンスにマージします。
- ソース シーケンス内の各要素の 1 つまたは複数のプロパティのみで構成される要素を持つ出力シーケンスを作成します。
- ソース データに対して実行された操作の結果で構成される要素を持つ出力シーケンスを作成します。
- 別の形式で出力シーケンスを作成します。 たとえば、SQL 行またはテキスト ファイルから XML にデータを変換できます。
これらの変換は、同じクエリでさまざまな方法で組み合わせることができます。 さらに、1 つのクエリの出力シーケンスを、新しいクエリの入力シーケンスとして使用できます。 次の例では、メモリ内のデータ構造内のオブジェクトを XML 要素に変換します。
// Create the query.
var studentsToXML = new XElement("Root",
from student in students
let scores = string.Join(",", student.Scores)
select new XElement("student",
new XElement("First", student.FirstName),
new XElement("Last", student.LastName),
new XElement("Scores", scores)
) // end "student"
); // end "Root"
// Execute the query.
Console.WriteLine(studentsToXML);
このコードでは、次の XML 出力が生成されます。
<Root>
<student>
<First>Svetlana</First>
<Last>Omelchenko</Last>
<Scores>97,90,73,54</Scores>
</student>
<student>
<First>Claire</First>
<Last>O'Donnell</Last>
<Scores>56,78,95,95</Scores>
</student>
...
<student>
<First>Max</First>
<Last>Lindgren</Last>
<Scores>86,88,96,63</Scores>
</student>
<student>
<First>Arina</First>
<Last>Ivanova</Last>
<Scores>93,63,70,80</Scores>
</student>
</Root>
詳細については、「 C# での XML ツリーの作成 (LINQ to XML)」を参照してください。
1 つのクエリの結果を、後続のクエリのデータ ソースとして使用できます。 この例では、結合操作の結果を並べ替える方法を示します。 このクエリでは、グループ結合を作成し、スコープ内にある category 要素に基づいてグループを並べ替えます。 匿名型初期化子内では、サブクエリは製品シーケンスから一致するすべての要素を並べ替えます。
var orderedQuery = from department in departments
join student in students on department.ID equals student.DepartmentID into studentGroup
orderby department.Name
select new
{
DepartmentName = department.Name,
Students = from student in studentGroup
orderby student.LastName
select student
};
foreach (var departmentList in orderedQuery)
{
Console.WriteLine(departmentList.DepartmentName);
foreach (var student in departmentList.Students)
{
Console.WriteLine($" {student.LastName,-10} {student.FirstName,-10}");
}
}
/* Output:
Chemistry
Balzan Josephine
Fakhouri Fadi
Popov Innocenty
Seleznyova Sofiya
Vella Carmen
Economics
Adams Terry
Adaobi Izuchukwu
Berggren Jeanette
Garcia Cesar
Ifeoma Nwanneka
Jamuike Ifeanacho
Larsson Naima
Svensson Noel
Ugomma Ifunanya
Engineering
Axelsson Erik
Berg Veronika
Engström Nancy
Hicks Cassie
Keever Bruce
Micallef Nicholas
Mortensen Sven
Nilsson Erna
Tucker Michael
Yermolayeva Anna
English
Andersson Sarah
Feng Hanying
Ivanova Arina
Jakobsson Jesper
Jensen Christiane
Johansson Mark
Kolpakova Nadezhda
Omelchenko Svetlana
Urquhart Donald
Mathematics
Frost Gaby
Garcia Hugo
Hedlund Anna
Kovaleva Katerina
Lindgren Max
Maslova Evgeniya
Olsson Ruth
Sammut Maria
Sazonova Anastasiya
Physics
Åkesson Sami
Edwards Amy E.
Falzon John
Garcia Debra
Hansson Sanna
Mattsson Martina
Richardson Don
Zabokritski Eugene
*/
次のコードでは、メソッド構文を使用した同等のクエリを示しています。
var orderedQuery = departments
.GroupJoin(students, department => department.ID, student => student.DepartmentID,
(department, studentGroup) => new
{
DepartmentName = department.Name,
Students = studentGroup.OrderBy(student => student.LastName)
})
.OrderBy(department => department.DepartmentName);
foreach (var departmentList in orderedQuery)
{
Console.WriteLine(departmentList.DepartmentName);
foreach (var student in departmentList.Students)
{
Console.WriteLine($" {student.LastName,-10} {student.FirstName,-10}");
}
}
結合の前に 1 つ以上のソース シーケンスで orderby
句を使用することはできますが、通常は推奨されません。 一部の LINQ プロバイダーでは、結合後にその順序が保持されない場合があります。 詳細については、結合句を参照してください。
こちらも参照ください
.NET