C#-Funktionen mit LINQ-Unterstützung
Abfrageausdrücke
Abfrageausdrücke verwenden eine deklarative Syntax wie SQL oder XQuery, um eine Abfrage über System.Collections.Generic.IEnumerable<T>-Sammlungen zu erstellen. Zur Kompilierzeit wird die Abfragesyntax in Methodenaufrufe in eine Implementierung des LINQ-Anbieters der Standardabfragemethoden konvertiert. Applikationen steuern die Standardabfrageoperatoren, die sich durch Angabe des entsprechenden Namespace mit einer using
-Anweisung innerhalb des Bereichs befinden. Der folgende Abfrageausdruck nimmt ein Array von Zeichenfolgen, gruppiert sie nach dem ersten Zeichen in der Zeichenfolge und sortiert die Gruppen.
var query = from str in stringArray
group str by str[0] into stringGroup
orderby stringGroup.Key
select stringGroup;
Implizit typisierte Variablen (var)
Sie können den var-Modifizierer verwenden, um den Compiler zum Ableiten und Zuweisen des Typs anzuweisen, wie hier gezeigt:
var number = 5;
var name = "Virginia";
var query = from str in stringArray
where str[0] == 'm'
select str;
Variablen, die als var
deklariert werden, sind ebenso stark typisiert wie Variablen, deren Typ Sie explizit angeben. Die Verwendung von var
macht es möglich, anonyme Typen zu erstellen, jedoch nur für lokale Variablen. Weitere Informationen finden Sie unter Implizit typisierte lokale Variablen.
Objekt- und Auflistungsinitialisierer
Objekt- und Auflistungsinitialisierer ermöglichen das Initialisieren von Objekten ohne expliziten Aufruf eines Konstruktors für das Objekt. Initialisierer werden in der Regel in Abfrageausdrücken verwendet, wenn sie die Quelldaten in einen neuen Datentyp projizieren. In einer Klasse namens Customer
mit öffentlichen Name
- und Phone
-Eigenschaften können Objektinitialisierer wie im folgenden Code verwendet werden:
var cust = new Customer { Name = "Mike", Phone = "555-1212" };
Wenn Sie mit der Customer
-Klasse fortfahren, gehen Sie davon aus, dass eine Datenquelle namens IncomingOrders
vorhanden ist und dass für jede Bestellung mit einem großen OrderSize
-Wert ein neues Customer
-Element basierend auf dieser Bestellung erstellt werden soll. Eine LINQ-Abfrage kann auf dieser Datenquelle ausgeführt werden und verwendet die Objektinitialisierung, um eine Auflistung zu füllen:
var newLargeOrderCustomers = from o in IncomingOrders
where o.OrderSize > 5
select new Customer { Name = o.Name, Phone = o.Phone };
Für die Datenquelle können mehr Eigenschaften definiert sein als für die Klasse Customer
, z. B. OrderSize
, aber bei der Objektinitialisierung werden die von der Abfrage zurückgegebenen Daten in den gewünschten Datentyp umgewandelt. Wählen Sie die Daten aus, die für Ihre Klasse relevant sind. Daher verfügen Sie jetzt über ein System.Collections.Generic.IEnumerable<T>-Element, das mit den neuen gewünschten Customer
-Informationen gefüllt ist. Das obige Beispiel kann auch in der Methodensyntax von LINQ geschrieben werden:
var newLargeOrderCustomers = IncomingOrders.Where(x => x.OrderSize > 5).Select(y => new Customer { Name = y.Name, Phone = y.Phone });
Ab C# 12 können Sie einen Sammlungsausdruck verwenden, um eine Sammlung zu initialisieren.
Weitere Informationen finden Sie unter:
Anonyme Typen
Der Compiler erstellt einen anonymen Typ. Der Typname ist nur für den Compiler verfügbar. Anonyme Typen stellen eine bequeme Möglichkeit zum vorübergehenden Gruppieren einer Reihe von Eigenschaften in einem Abfrageergebnis bereit, ohne einen separaten benannten Typ definieren zu müssen. Anonyme Typen werden mit einem neuen Ausdruck und einem Objektinitialisierer initialisiert, wie hier gezeigt:
select new {name = cust.Name, phone = cust.Phone};
Ab C# 7 können Sie Tupel verwenden, um unbenannte Typen zu erstellen.
Erweiterungsmethoden
Eine Erweiterungsmethode ist eine statische Methode, die einem Typ zugeordnet werden kann, sodass sie aufgerufen werden kann, als ob es sich um eine Instanzmethode für den Typ handeln würde. Diese Funktion ermöglicht es Ihnen, neue Methoden zu vorhandenen Typen „hinzuzufügen“, ohne sie tatsächlich zu ändern. Die Standardabfrageoperatoren sind eine Reihe von Erweiterungsmethoden, die LINQ-Abfragefunktionen für jeden Typ bieten, der IEnumerable<T> implementiert.
Lambda-Ausdrücke
Ein Lambdaausdruck ist eine Inlinefunktion, die den Operator =>
verwendet, um Eingabeparameter vom Funktionstext zu trennen, und die zur Kompilierzeit in einen Delegaten oder eine Ausdrucksbaumstruktur konvertiert werden kann. In der LINQ-Programmierung erhalten Sie Lambdaausdrücke, wenn Sie direkte Methodenaufrufe für die Standardabfrageoperatoren vornehmen.
Ausdrücke als Daten
Abfrageobjekte sind zusammensetzbar, das bedeutet, dass Sie eine Abfrage aus einer Methode zurückgeben können. Objekte, die Abfragen darstellen, speichern nicht die resultierende Auflistung, sondern bei Bedarf die Schritte zum Erzeugen der Ergebnisse. Der Vorteil des Zurückgebens von Abfrageobjekten aus Methoden ist, dass diese weiter zusammengesetzt oder geändert werden können. Daher muss ein Rückgabewert oder ein out
-Parameter einer Methode, die eine Abfrage zurückgibt, über diesen Typ verfügen. Wenn eine Methode eine Abfrage in den konkreten Typ List<T> oder Array materialisiert, gibt sie die Abfrageergebnisse zurück, nicht die Abfrage selbst. Eine Abfragevariable, die aus einer Methode zurückgegeben wird, kann noch zusammengesetzt oder geändert werden.
Im folgenden Beispiel gibt die erste Methode QueryMethod1
eine Abfrage als Rückgabewert zurück. Die zweite Methode QueryMethod2
gibt eine Abfrage als out
-Parameter (returnQ
im Beispiel) zurück. In beiden Fällen handelt es sich um eine Abfrage, die zurückgegeben wird, nicht um Abfrageergebnisse.
IEnumerable<string> QueryMethod1(int[] ints) =>
from i in ints
where i > 4
select i.ToString();
void QueryMethod2(int[] ints, out IEnumerable<string> returnQ) =>
returnQ =
from i in ints
where i < 4
select i.ToString();
int[] nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
var myQuery1 = QueryMethod1(nums);
Abfrage myQuery1
wird in der folgenden Foreachschleife ausgeführt.
foreach (var s in myQuery1)
{
Console.WriteLine(s);
}
Positionieren Sie den Mauszeiger über myQuery1
, um den Typ anzuzeigen.
Sie können auch die von QueryMethod1
zurückgegebene Abfrage direkt ausführen, ohne myQuery1
zu verwenden.
foreach (var s in QueryMethod1(nums))
{
Console.WriteLine(s);
}
Positionieren Sie den Mauszeiger über dem Aufruf an QueryMethod1
, um den Rückgabetyp anzuzeigen.
QueryMethod2
gibt eine Abfrage als Wert ihres out
-Parameters zurück:
QueryMethod2(nums, out IEnumerable<string> myQuery2);
// Execute the returned query.
foreach (var s in myQuery2)
{
Console.WriteLine(s);
}
Sie können eine Abfrage mithilfe der Abfragekomposition ändern. In diesem Fall wird das vorherige Abfrageobjekt verwendet, um ein neues Abfrageobjekt zu erstellen. Dieses neue Objekt gibt andere Ergebnisse als das ursprüngliche Abfrageobjekt zurück.
myQuery1 =
from item in myQuery1
orderby item descending
select item;
// Execute the modified query.
Console.WriteLine("\nResults of executing modified myQuery1:");
foreach (var s in myQuery1)
{
Console.WriteLine(s);
}