Abfragesyntax und Methodensyntax in LINQ (C#)
Die meisten Abfragen in der einführende Dokumentation Language Integrated Query (LINQ) geschrieben werden, indem die deklarativen Abfragesyntax LINQs verwendet. muss jedoch die Abfragesyntax in Methodenaufrufe für die.NET Common Language Runtime (CLR) übersetzt werden wenn der Code kompiliert wird. Diese Methodenaufrufe rufen die Standardabfrageoperatoren aufgelistet, die Namen wie Where, Select, GroupBy, Join, Max und Average haben. Sie können sie direkt aufrufen, indem Sie Methodensyntax statt der Abfragesyntax verwenden.
Abfragesyntax und Methodensyntax sind semantisch identisch, jedoch viele Personen suchen das einfachere und besser lesbar Abfragesyntax. Einige Abfragen müssen als Methodenaufrufe ausgedrückt werden. Beispielsweise müssen Sie einen Methodenaufruf verwenden, um eine Abfrage auszudrücken, die die Anzahl von Elementen abgerufen werden, die eine bestimmte Bedingung übereinstimmen. Sie müssen einen Methodenaufruf für eine Abfrage auch verwenden, die das Element abruft, 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.
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-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.
Obwohl es scheint, als ob IEnumerable 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, 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.
Lambda-Ausdrücke
Beachten Sie im vorigen Beispiel, dass der bedingte Ausdruck (num % 2 == 0) als Inlineargument an die Methode übergeben wird: WhereWhere(num => num % 2 == 0). dieser Inlineausdruck wird Lambda-Ausdruck aufgerufen. 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-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.