Freigeben über


Typbeziehungen in LINQ-Abfragevorgängen (C#)

Um Abfragen effektiv zu schreiben, sollten Sie verstehen, wie sich die Typen der Variablen in einem vollständigen Abfragevorgang miteinander in Beziehung setzen. Wenn Sie diese Beziehungen verstehen, verstehen Sie die LINQ-Beispiele und Codebeispiele in der Dokumentation einfacher. Darüber hinaus werden Sie verstehen, was geschieht, wenn Variablen durch die Verwendung von var implizit typisiert werden.

LINQ-Abfrageoperationen sind in der Datenquelle, in der Abfrage selbst und in der Abfrageausführung stark typisiert. Der Typ der Variablen in der Abfrage muss mit dem Typ der Elemente in der Datenquelle und mit dem Typ der Iterationsvariablen in der foreach Anweisung kompatibel sein. Diese starke Eingabe garantiert, dass Typfehler zur Kompilierzeit abgefangen werden, wenn sie korrigiert werden können, bevor benutzer auf sie stoßen.

Um diese Typbeziehungen zu veranschaulichen, verwenden die meisten der folgenden Beispiele eine explizite Typisierung für alle Variablen. Das letzte Beispiel zeigt, wie die gleichen Prinzipien angewendet werden, auch wenn Sie mit impliziter Typisierung mithilfe von var arbeiten.

Abfragen, die die Quelldaten nicht transformieren

Die folgende Abbildung zeigt einen LINQ to Objects-Abfragevorgang, der keine Transformationen für die Daten ausführt. Die Quelle enthält eine Abfolge von Zeichenfolgen, und die Abfrageausgabe ist auch eine Abfolge von Zeichenfolgen.

Diagramm, das die Beziehung von Datentypen in einer LINQ-Abfrage zeigt.

  1. Das Typargument der Datenquelle bestimmt den Typ der Bereichsvariable.
  2. Der Typ des ausgewählten Objekts bestimmt den Typ der Abfragevariable. Hier name ist eine Zeichenfolge. Daher ist die Abfragevariable eine IEnumerable<string>.
  3. Die Abfragevariable durchläuft in der foreach-Anweisung verschiedene Iterationen. Da es sich bei der Abfragevariable um eine Abfolge von Zeichenfolgen handelt, ist die Iterationsvariable auch eine Zeichenfolge.

Abfragen, die die Quelldaten transformieren

Die folgende Abbildung zeigt einen LINQ to SQL-Abfragevorgang, der eine einfache Transformation der Daten durchführt. Die Abfrage akzeptiert eine Abfolge von Customer Objekten als Eingabe und wählt nur die Name Eigenschaft im Ergebnis aus. Da Name es sich um eine Zeichenfolge handelt, erzeugt die Abfrage eine Abfolge von Zeichenfolgen als Ausgabe.

Diagramm mit einer Abfrage, die den Datentyp transformiert.

  1. Das Typargument der Datenquelle bestimmt den Typ der Bereichsvariable.
  2. Die select Anweisung gibt die Name Eigenschaft anstelle des vollständigen Customer Objekts zurück. Da Name eine Zeichenfolge ist, ist das Typargument von custNameQuerystring, nicht Customer.
  3. Da custNameQuery es sich um eine Abfolge von Zeichenfolgen handelt, muss die Iterationsvariable der foreach Schleife auch eine string sein.

Die folgende Abbildung zeigt eine etwas komplexere Transformation. Die select Anweisung gibt einen anonymen Typ zurück, der nur zwei Member des ursprünglichen Customer Objekts erfasst.

Diagramm mit einer komplexeren Abfrage, die den Datentyp transformiert.

  1. Das Typargument der Datenquelle ist immer der Typ der Bereichsvariable in der Abfrage.
  2. Da die select Anweisung einen anonymen Typ erzeugt, muss die Abfragevariable implizit mithilfe von var typisiert werden.
  3. Da der Typ der Abfragevariable implizit ist, muss die Iterationsvariable in der foreach Schleife ebenfalls implizit sein.

Dem Compiler erlauben, Typinformationen abzuleiten.

Obwohl Sie die Typbeziehungen in einem Abfragevorgang verstehen sollten, haben Sie die Möglichkeit, dem Compiler die gesamte Arbeit für Sie zu ermöglichen. Das var-Schlüsselwort kann für jede lokale Variable in einem Abfragevorgang verwendet werden. Die folgende Abbildung ähnelt beispielnummer 2, die zuvor erläutert wurde. Der Compiler stellt jedoch den starken Typ für jede Variable im Abfragevorgang zur Verfügung.

Diagramm, das den Typfluss mit impliziter Eingabe zeigt.

LINQ- und generische Typen (C#)

LINQ-Abfragen basieren auf generischen Typen. Sie benötigen kein fundiertes Wissen über Generika, bevor Sie mit dem Schreiben von Abfragen beginnen können. Möglicherweise möchten Sie jedoch zwei grundlegende Konzepte verstehen:

  1. Wenn Sie eine Instanz einer generischen Auflistungsklasse erstellen, wie List<T>, ersetzen Sie das „T“ durch den Typ der Objekte, die die Liste enthält. Beispielsweise wird eine Liste von Zeichenfolgen als ausgedrückt List<string>, und eine Liste von Customer Objekten wird als ausgedrückt List<Customer>. Eine generische Liste ist stark typisiert und bietet viele Vorteile gegenüber Sammlungen, die ihre Elemente als Object speichern. Wenn Sie versuchen, ein Customer zu einem List<string> hinzuzufügen, wird zur Kompilierungszeit ein Fehler angezeigt. Es ist sehr leicht, generische Auflistungen zu verwenden, da Sie keine Laufzeitumwandlung von Typen durchführen müssen.
  2. IEnumerable<T> ist die Schnittstelle, mit der generische Auflistungsklassen mithilfe der foreach Anweisung aufgezählt werden können. Generische Auflistungsklassen unterstützen IEnumerable<T>, während nicht generische Auflistungsklassen, wie etwa ArrayList, IEnumerable unterstützen.

Weitere Informationen zu Generika finden Sie unter Generics.

IEnumerable<T>-Variablen in LINQ-Abfragen

LINQ-Abfragevariablen sind als IEnumerable<T> oder als ein abgeleiteter Typ wie IQueryable<T> typisiert. Wenn eine Abfragevariable angezeigt wird, die als IEnumerable<Customer>eingegeben wird, bedeutet dies lediglich, dass die Abfrage, wenn sie ausgeführt wird, eine Sequenz von Null oder mehr Customer Objekten erzeugt.

IEnumerable<Customer> customerQuery = from cust in customers
                                      where cust.City == "London"
                                      select cust;

foreach (Customer customer in customerQuery)
{
    Console.WriteLine($"{customer.LastName}, {customer.FirstName}");
}

Verwalten generischer Typdeklarationen durch den Compiler

Wenn Sie es vorziehen, können Sie generische Syntax vermeiden, indem Sie das Schlüsselwort var verwenden. Das var Schlüsselwort weist den Compiler an, den Typ einer Abfragevariable abzuleiten, indem er die in der from Klausel angegebene Datenquelle betrachtet. Im folgenden Beispiel wird der gleiche kompilierte Code wie im vorherigen Beispiel erzeugt:

var customerQuery2 = from cust in customers
                     where cust.City == "London"
                     select cust;

foreach(var customer in customerQuery2)
{
    Console.WriteLine($"{customer.LastName}, {customer.FirstName}");
}

Das var Schlüsselwort ist nützlich, wenn der Typ der Variablen offensichtlich ist oder wenn es nicht so wichtig ist, geschachtelte generische Typen wie gruppenabfragen explizit anzugeben. Im Allgemeinen empfiehlt es sich, wenn Sie verwenden var, zu erkennen, dass der Code für andere Benutzer schwieriger zu lesen ist. Weitere Informationen finden Sie unter Implizit typierten lokalen Variablen.