from 句 (C# リファレンス)

更新 : 2007 年 11 月

クエリ式は、from 句で始める必要があります。また、クエリ式に含めることができるサブクエリも from 句で始めます。from 句では、次の内容が指定されます。

  • クエリまたはサブクエリが実行されるデータ ソース。

  • ソース シーケンス内の各要素を表すローカルの範囲変数。

範囲変数とデータ ソースは両方とも厳密に型指定されます。from 句で参照されるデータ ソースの型は、IEnumerableIEnumerable<T>、または派生型 (たとえば IQueryable<T>) です。

次の例では、numbers がデータ ソースで、num が範囲変数です。var キーワードを使用する場合でも、両方の変数は厳密に型指定されます。

class LowNums
{
    static void Main()
    {   
        // A simple data source.
        int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

        // Create the query.
        // lowNums is an IEnumerable<int>
        var lowNums = from num in numbers
            where num < 5
            select num;

        // Execute the query.
        foreach (int i in lowNums)
        {
            Console.Write(i + " ");
        }
    }        
}
// Output: 4 1 3 2 0

範囲変数

データ ソースが IEnumerable<T> を実装するときに、コンパイラは範囲変数の型を推論します。たとえば、ソースの型が IEnumerable<Customer> の場合、範囲変数は Customer であると推論されます。型を明示的に指定する必要があるのは、ソースが ArrayList などの非ジェネリックの IEnumerable 型の場合のみです。詳細については、「方法 : LINQ を使用して ArrayList を照会する」を参照してください。

上の例では、num は int 型と推論されます。範囲変数は厳密に型指定されるため、範囲変数でメソッドを呼び出したり、他の操作で範囲変数を使用したりできます。たとえば、select num と記述する代わりに、クエリ式が整数ではなく文字列のシーケンスを返すように select num.ToString() と記述できます。式がシーケンス 14、11、13、12、10 を返すように、select n + 10 と記述することもできます。詳細については、「select 句 (C# リファレンス)」を参照してください。

範囲変数は foreach ステートメントの繰り返し変数に似ていますが、範囲変数は実際にはソースのデータを格納しない点が異なります。範囲変数は、構文を簡略化します。これを使用すると、クエリが実行されるときの処理の内容を表すことができます。詳細については、「LINQ クエリの概要」を参照してください。

複合 from 句

ソース シーケンス内の各要素がそれ自体でシーケンスであったり、シーケンスを含んでいたりする場合があります。たとえば、データ ソースが IEnumerable<Student> で、そのシーケンス内の各学生オブジェクトがテストの得点の一覧を含む場合があります。各 Student 要素内の内部一覧にアクセスするために、複合 from 句を使用できます。この方法は、入れ子になった foreach ステートメントを使用するのに似ています。いずれかの from 句に where 句または orderby 句を追加して、結果をフィルタ処理します。Student オブジェクトのシーケンスを次の例に示します。各オブジェクトには、テストの得点を表す整数の内部 List が含まれます。内部一覧にアクセスするには、複合 from 句を使用します。必要に応じて、2 つの from 句の間に句を挿入できます。

class CompoundFrom
{
    // The element type of the data source.
    public class Student
    {
        public string LastName { get; set; }
        public List<int> Scores {get; set;}
    }

    static void Main()
    {

        // Use a collection initializer to create the data source. Note that 
        // each element in the list contains an inner sequence of scores.
        List<Student> students = new List<Student>
        {
           new Student {LastName="Omelchenko", Scores= new List<int> {97, 72, 81, 60}},
           new Student {LastName="O'Donnell", Scores= new List<int> {75, 84, 91, 39}},
           new Student {LastName="Mortensen", Scores= new List<int> {88, 94, 65, 85}},
           new Student {LastName="Garcia", Scores= new List<int> {97, 89, 85, 82}},
           new Student {LastName="Beebe", Scores= new List<int> {35, 72, 91, 70}} 
        };        

        // Use a compound from to access the inner sequence within each element.
        // Note the similarity to a nested foreach statement.
        var scoreQuery = from student in students
                         from score in student.Scores
                            where score > 90
                            select new { Last = student.LastName, score };

        // Execute the queries.
        Console.WriteLine("scoreQuery:");
        foreach (var student in scoreQuery)
        {
            Console.WriteLine("{0} Score: {1}", student.Last, student.score);
        }

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }       
}
/*
scoreQuery:
Omelchenko Score: 97
O'Donnell Score: 91
Mortensen Score: 94
Garcia Score: 97
Beebe Score: 91
*/

複数の from 句を使用した結合の実行

複合 from 句は、単一データ ソース内の内部コレクションにアクセスするために使用されます。ただし、独立したデータ ソースから補足するクエリを生成する複数の from 句をクエリに含めることもできます。この方法により、join 句では実行できない特定の種類の結合操作を実行できます。

2 つの from 句を使用して、2 つのデータ ソースの完全なクロス結合を作成する方法を次の例に示します。

class CompoundFrom2
{
    static void Main()
    {              
        char[] upperCase = { 'A', 'B', 'C'};
        char[] lowerCase = { 'x', 'y', 'z'};

        var joinQuery1 =
            from upper in upperCase
            from lower in lowerCase
                select new { upper, lower};

        var joinQuery2 =
            from lower in lowerCase
            where lower != 'x'
            from upper in upperCase
            select new { lower, upper };


        // Execute the queries.
        Console.WriteLine("Cross join:");
        foreach (var pair in joinQuery1)
        {
            Console.WriteLine("{0} is matched to {1}", pair.upper, pair.lower);
        }

        Console.WriteLine("Filtered non-equijoin:");
        foreach (var pair in joinQuery2)
        {
            Console.WriteLine("{0} is matched to {1}", pair.lower, pair.upper);
        }

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Output:
        Cross join:
        A is matched to x
        A is matched to y
        A is matched to z
        B is matched to x
        B is matched to y
        B is matched to z
        C is matched to x
        C is matched to y
        C is matched to z
        Filtered non-equijoin:
        y is matched to A
        y is matched to B
        y is matched to C
        z is matched to A
        z is matched to B
        z is matched to C
        */

複数の from 句を使用する結合操作の詳細については、「方法 : カスタム結合操作を実行する (C# プログラミング ガイド)」を参照してください。

参照

概念

LINQ クエリ式 (C# プログラミング ガイド)

その他の技術情報

クエリ キーワード (C# リファレンス)