次の方法で共有


標準クエリ演算子の概要

標準クエリ演算子は、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 への参照を持っています。

ソース リポジトリでデータ セットを見つけることができます。

クエリ演算子の種類

標準クエリ演算子は、シングルトン値と値のシーケンスのどちらを返すかによって、実行のタイミングが異なります。 シングルトン値を返すメソッド ( AverageSumなど) は直ちに実行されます。 シーケンスを返すメソッドは、クエリの実行を延期し、列挙可能なオブジェクトを返します。 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 キーワードを使用します。

クエリ式の構文表

次の表に、同等のクエリ式句を持つ標準クエリ演算子を示します。

メソッド C# クエリ式の構文
Cast 明示的に型指定された範囲変数を使用します。

from int i in numbers

(詳しくは、「from 句」をご覧ください。)
GroupBy group … by

-又は-

group … by … into …

(詳細については、グループ句を参照してください)。
GroupJoin<TOuter,TInner,TKey,TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter,TKey>, Func<TInner,TKey>, Func<TOuter,IEnumerable<TInner>, TResult>) join … in … on … equals … into …

(詳細については、結合句を参照してください)。
Join<TOuter,TInner,TKey,TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter,TKey>, Func<TInner,TKey>, Func<TOuter,TInner,TResult>) join … in … on … equals …

(詳細については、結合句を参照してください)。
OrderBy<TSource,TKey>(IEnumerable<TSource>, Func<TSource,TKey>) orderby

(詳しくは、「orderby 句」をご覧ください。)
OrderByDescending<TSource,TKey>(IEnumerable<TSource>, Func<TSource,TKey>) orderby … descending

(詳しくは、「orderby 句」をご覧ください。)
Select select

(詳細については、SELECT句をご覧ください)。
SelectMany 複数の from 句を使用します。

(詳しくは、「from 句」をご覧ください。)
ThenBy<TSource,TKey>(IOrderedEnumerable<TSource>, Func<TSource,TKey>) orderby …, …

(詳しくは、「orderby 句」をご覧ください。)
ThenByDescending<TSource,TKey>(IOrderedEnumerable<TSource>, Func<TSource,TKey>) orderby …, … descending

(詳しくは、「orderby 句」をご覧ください。)
Where where

(詳細については、 where 句を参照してください)。

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 プロバイダーでは、結合後にその順序が保持されない場合があります。 詳細については、結合句を参照してください。

こちらも参照ください