from-Klausel (C#-Referenz)

Aktualisiert: November 2007

Ein Abfrageausdruck muss mit einer from-Klausel beginnen. Darüber hinaus kann ein Abfrageausdruck Unterabfragen enthalten, die auch mit einer from-Klausel beginnen. Die from-Klausel gibt Folgendes an:

  • Die Datenquelle, für die die Abfrage oder Unterabfrage ausgeführt wird.

  • Eine lokale Bereichsvariable, die jedes Element in der Quellsequenz darstellt.

Sowohl die Bereichsvariable als auch die Datenquelle sind stark typisiert. Auf die in der from-Klausel verwiesene Datenquelle muss vom Typ IEnumerable, IEnumerable<T> oder von einem abgeleiteten Typ wie IQueryable<T> sein.

Im folgenden Beispiel ist numbers die Datenquelle, und num ist die Bereichsvariable. Beachten Sie, dass beide Variablen stark typisiert sind, obwohl sogar das var-Schlüsselwort verwendet wird.

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

Die Bereichsvariable

Der Compiler leitet den Typ der Bereichsvariablen ab, wenn die Datenquelle IEnumerable<T> implementiert. Wenn die Quelle beispielsweise vom Typ IEnumerable<Customer> ist, wird die Bereichsvariable als Customer abgeleitet. Sie müssen den Typ nur explizit angeben, wenn die Quelle ein nicht-generischer IEnumerable-Typ wie z. B. ArrayList ist. Weitere Informationen hierzu finden Sie unter Gewusst wie: Abfragen von ArrayList mit LINQ.

Im vorherigen Beispiel wird num als Typ int abgeleitet. Da die Bereichsvariable eine sehr starke Typisierung aufweist, können Sie für sie Methoden aufrufen oder sie in anderen Operationen verwenden. Anstatt z. B. select num zu schreiben, könnten Sie select num.ToString() schreiben, sodass der Abfrageausdruck eine Sequenz von Zeichenfolgen anstelle von Ganzzahlen zurückgibt. Sie könnten auch select n + 10 schreiben, damit der Ausdruck die Sequenz 14, 11, 13, 12, 10 zurückgibt. Weitere Informationen hierzu finden Sie unter select-Klausel (C#-Referenz).

Die Bereichsvariable entspricht einer Iterationsvariablen in einer foreach-Anweisung mit einer wichtigen Ausnahme: Eine Bereichsvariable speichert niemals Daten aus der Quelle. Sie ist nur ein syntaktisches Hilfsmittel, mit dem die Abfrage beschreiben kann, was eintritt, wenn die Abfrage ausgeführt wird. Weitere Informationen hierzu finden Sie unter Einführung in LINQ-Abfragen.

Zusammengesetzte from-Klauseln

In einigen Fällen kann jedes Element in der Quellsequenz selbst eine Sequenz sein oder eine Sequenz enthalten. Ihre Datenquelle kann beispielsweise ein IEnumerable<Student> sein, wobei jedes Student-Objekt in der Sequenz eine Liste der Testergebnisse enthält. Um auf die innere Liste innerhalb jedes Student-Elements zuzugreifen, können Sie zusammengesetzte from-Klauseln verwenden. Die Technik entspricht dem Verwenden von geschachtelten foreach-Anweisungen. Sie können die where-Klausel oder die orderby-Klausel zu einer der beiden from-Klauseln hinzufügen, um die Ergebnisse zu filtern. Das folgende Beispiel enthält eine Sequenz von Student-Objekten, von denen jedes eine innere List mit Ganzzahlen enthält, die die Testergebnisse darstellen. Um auf die innere Liste zuzugreifen, verwenden Sie eine zusammengesetzte from-Klausel. Bei Bedarf können Sie Klauseln zwischen den beiden from-Klauseln einfügen.

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
*/

Verwenden von mehreren from-Klauseln zum Ausführen von Verknüpfungen

Eine zusammengesetzte from-Klausel wird zum Zugriff auf innere Auflistungen in einer einzelnen Datenquelle verwendet. Eine Abfrage kann jedoch auch mehrere from-Klauseln enthalten, die ergänzende Abfragen aus unabhängigen Datenquellen generieren. Mit dieser Technik können Sie bestimmte Typen von Verknüpfungsoperationen durchführen, die beim Einsatz der join-Klausel nicht möglich sind.

Das folgende Beispiel veranschaulicht, wie zwei from-Klauseln verwendet werden können, um eine vollständige Kreuzverknüpfung zweier Datenquellen zu bilden.

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
        */

Weitere Informationen zu Verknüpfungsoperationen mit mehreren from-Klauseln finden Sie unter Gewusst wie: Ausführen von benutzerdefinierten Verknüpfungsoperationen (C#-Programmierhandbuch).

Siehe auch

Konzepte

LINQ-Abfrageausdrücke (C#-Programmierhandbuch)

Weitere Ressourcen

Abfrageschlüsselwörter (C#-Referenz)