Freigeben über


LINQ-Abfragesyntax und Methodensyntax (C#)

Die meisten Abfragen in der einführenden LINQ-Dokumentation sind als Abfrageausdrücke mit der deklarativen, in C# 3.0 eingeführten Abfragesyntax geschrieben. In der .NET Common Language Runtime (CLR) ist jedoch kein Konzept einer Abfragesyntax enthalten. Zur Kompilierzeit werden deshalb Abfrageausdrücke in Methodenaufrufe übersetzt, die von der CLR verstanden werden. Diese Methoden werden auch als Standardabfrageoperatoren bezeichnet und haben Namen wie Where, Select, GroupBy, Join, Max oder Average. Sie können sie direkt aufrufen, indem Sie Methodensyntax statt der Abfragesyntax verwenden.

Im Allgemeinen empfehlen wir die Abfragesyntax, da sie in der Regel einfacher und besser lesbar ist, es besteht jedoch kein semantischer Unterschied zwischen Methodensyntax und Abfragesyntax. Darüber hinaus können einige Abfragen nur als Methodenaufrufe ausgedrückt werden, z. B. solche, die die Anzahl der Elemente abrufen, die einer bestimmten Bedingung entsprechen, oder das Element abrufen, das den maximalen Wert in einer Quellsequenz hat. Die Referenzdokumentation für die Standardabfrageoperatoren im System.Linq-Namespace verwendet im Allgemeinen Methodensyntax. Daher ist es auch bei den ersten selbst geschriebenen LINQ-Abfragen hilfreich, zu wissen, wie Methodensyntax in Abfragen und Abfrageausdrücken selbst verwendet wird.

Standardabfrageoperator-Erweiterungsmethoden

Im folgenden Beispiel werden ein einfacher Abfrageausdruck und die semantisch ähnliche Abfrage gezeigt, die als methodenbasierte Abfrage geschrieben wird.

class QueryVMethodSyntax
{
    static void Main()
    {
        int[] numbers = { 5, 10, 8, 3, 6, 12};

        //Query syntax:
        IEnumerable<int> numQuery1 = 
            from num in numbers
            where num % 2 == 0
            orderby num
            select num;

        //Method syntax:
        IEnumerable<int> numQuery2 = numbers.Where(num => num % 2 == 0).OrderBy(n => n);

        foreach (int i in numQuery1)
        {
            Console.Write(i + " ");
        }
        Console.WriteLine(System.Environment.NewLine);
        foreach (int i in numQuery2)
        {
            Console.Write(i + " ");
        }

        // Keep the console open in debug mode.
        Console.WriteLine(System.Environment.NewLine);
        Console.WriteLine("Press any key to exit");
        Console.ReadKey();
    }
}
/*
    Output:
    6 8 10 12
    6 8 10 12
 */

Die Ausgabe der beiden Beispiele ist identisch. Sie können sehen, dass der Typ der Abfragevariablen in beiden Fällen der gleiche ist: IEnumerable<T>.

Um methodenbasierte Abfragen zu verstehen, müssen wir sie genauer untersuchen. Auf der rechten Seite des Ausdrucks wird die where-Klausel jetzt als Instanzenmethode für das numbers-Objekt ausgedrückt, das wie bereits erwähnt vom Typ IEnumerable<int> ist. Wenn Sie mit der generischen IEnumerable<T>-Schnittstelle vertraut sind, wissen Sie, dass diese keine Where-Methode aufweist. Wenn Sie jedoch die IntelliSense-Vervollständigungsliste in der Visual Studio IDE aufrufen, sehen Sie nicht nur eine Where-Methode, sondern auch viele anderen Methoden, z. B. Select, SelectMany, Join und Orderby. Dies sind alle Standardabfrageoperatoren.

Standardabfrageoperatoren in Intellisense

Obwohl es scheint, als ob IEnumerable<T> so umdefiniert wurde, das diese zusätzlichen Methoden enthalten sind, ist dies in der Tat nicht der Fall. Die Standardabfrageoperatoren werden als neue Art von Methode mit der Bezeichnung Erweiterungsmethoden implementiert. Erweiterungsmethoden "erweitern" einen vorhandenen Typ; sie können wie Instanzenmethoden für den Typ aufgerufen werden. Die Standardabfrageoperatoren erweitern IEnumerable<T>, und daher können Sie numbers.Where(...) schreiben.

Um mit der Verwendung von LINQ zu beginnen, müssen Sie lediglich wissen, wie Sie die Erweiterungsmethoden in Ihre Anwendung unter Verwendung der richtigen using-Direktiven einbinden. Dies wird darüber hinaus in Gewusst wie: Erstellen eines LINQ-Projekts erklärt. Aus der Perspektive der Anwendung sind eine Erweiterungsmethode und eine reguläre Instanzenmethode das Gleiche.

Weitere Informationen über Erweiterungsmethoden finden Sie unter Erweiterungsmethoden (C#-Programmierhandbuch). Weitere Informationen über Standardabfrageoperatoren finden Sie unter Übersicht über Standardabfrageoperatoren. Einige LINQ-Anbieter, wie z. B. LINQ to SQL und LINQ to XML, implementieren ihre eigenen Standardabfrageoperatoren und zusätzlichen Erweiterungsmethoden für andere Typen außer IEnumerable<T>.

Lambda-Ausdrücke

Beachten Sie im vorigen Beispiel, dass der Bedingungsausdruck (num % 2 == 0) als Inlineargument an die Where-Methode übergeben wird: Where(num => num % 2 == 0). Dieser Inlineausdruck wird als Lambda-Ausdruck bezeichnet. Dies ist eine praktische Möglichkeit, Code zu schreiben, der ansonsten in einer komplexeren Form als anonyme Methode, generischer Delegat oder Ausdrucksbaumstruktur geschrieben werden müsste. In C# ist => der Lambda-Operator, der so viel bedeutet wie "wechselt zu". num auf der linken Seite des Operators ist die Eingabevariable, die num im Abfrageausdruck entspricht. Der Compiler kann den Typ num ableiten, da er weiß, dass numbers ein generischer IEnumerable<T>-Typ ist. Der Text des Lambda-Ausdrucks entspricht dem Ausdruck in der Abfragesyntax oder jedem anderen C#-Ausdruck bzw. jeder anderen C#-Anweisung; er kann Methodenaufrufe und andere komplexe Logik umfassen. Der "Rückgabewert" ist nur das Ergebnis des Ausdrucks.

Wenn Sie mit der Verwendung von LINQ beginnen, müssen Sie Lambdas nicht sofort umfassend einsetzen. Bestimmte Abfragen können jedoch nur in Methodensyntax ausgedrückt werden, und einige davon erfordern Lambda-Ausdrücke. Nachdem Sie sich mit Lambdas vertraut gemacht haben, werden Sie feststellen, dass sie ein leistungsstarkes und flexibles Tool der LINQ-Toolbox sind. Weitere Informationen finden Sie unter Lambda-Ausdrücke (C#-Programmierhandbuch).

Zusammensetzbarkeit von Abfragen

Im vorherigen Codebeispiel wurde die OrderBy-Methode durch Verwendung des Punktoperators für den Aufruf von Where aufgerufen. Where erzeugt eine gefilterte Sequenz. Anschließend wird Orderby zum Sortieren dieser Sequenz ausgeführt. Da Abfragen IEnumerable zurückgeben, setzen Sie sie in Methodensyntax zusammen, indem Sie die Methodenaufrufe verketten. Dies ist, was der Compiler im Hintergrund macht, wenn Sie Abfragen durch Verwendung der Abfragesyntax schreiben. Und da eine Abfragevariable nicht die Ergebnisse der Abfrage speichert, können Sie sie jederzeit ändern oder als Grundlage für eine neue Abfrage verwenden, auch wenn sie ausgeführt wurde.

Siehe auch

Weitere Ressourcen

Erste Schritte mit LINQ in C#