Typbeziehungen in Abfrageoperationen (Visual Basic)

Variablen, die in LINQ-Abfragevorgängen (Language-Integrated Query) verwendet werden, sind stark typisiert und müssen miteinander kompatibel sein. Starke Typisierung wird in der Datenquelle, in der Abfrage selbst und in der Abfrageausführung verwendet. In der folgenden Abbildung werden Begriffe identifiziert, die zum Beschreiben einer LINQ-Abfrage verwendet werden. Weitere Informationen zu den Komponenten einer Abfrage finden Sie unter Grundlegende Abfragevorgänge (Visual Basic).

Screenshot showing a pseudocode query with elements highlighted.

Der Typ der Bereichsvariablen in der Abfrage muss mit dem Typ der Elemente in der Datenquelle kompatibel sein. Der Typ der Abfragevariable muss mit dem in der Select-Klausel definierten Sequenzelement kompatibel sein. Schließlich muss der Typ der Sequenzelemente auch mit dem Typ der Schleifensteuerungsvariablen kompatibel sein, der in der For Each-Anweisung verwendet wird, die die Abfrage ausführt. Diese starke Typisierung erleichtert die Identifizierung von Typfehlern zur Kompilierzeit.

In Visual Basic wird starke Typisierung durch die Implementierung von lokalem Typrückschluss erleichtert, der auch als implizite Typisierung bezeichnet wird. Diese Funktion wird im vorherigen Beispiel verwendet, und Sie werden sehen, dass sie in allen LINQ-Beispielen und der Dokumentation verwendet wird. In Visual Basic erfolgt der lokale Typrückschluss einfach mithilfe einer Dim-Anweisung ohne As-Klausel. Im folgenden Beispiel ist city als Zeichenfolge stark typisiert.

Dim city = "Seattle"

Hinweis

Lokaler Typrückschluss funktioniert nur, wenn Option Infer auf On festgelegt ist. Weitere Informationen finden Sie unter Option Infer-Anweisung.

Aber auch wenn Sie in einer Abfrage lokalen Typrückschluss verwenden, bestehen zwischen den Variablen in der Datenquelle, den Abfragevariablen und der Abfrageausführungsschleife die gleichen Typbeziehungen. Es ist nützlich, ein grundlegendes Verständnis für diese Typbeziehungen zu haben, wenn Sie LINQ-Abfragen schreiben oder mit den Beispielen und Codebeispielen in der Dokumentation arbeiten.

Möglicherweise müssen Sie einen expliziten Typ für eine Bereichsvariable angeben, die nicht mit dem von der Datenquelle zurückgegebenen Typ übereinstimmt. Sie können den Typ der Bereichsvariablen mithilfe einer As-Klausel angeben. Dies führt jedoch zu einem Fehler, wenn die Konvertierung eine einschränkende Konvertierung ist und Option Strict auf On festgelegt ist. Daher wird empfohlen, die Konvertierung für die aus der Datenquelle abgerufenen Werte durchzuführen. Sie können die Werte aus der Datenquelle mit der Cast-Methode in den expliziten Bereichsvariablentyp konvertieren. Sie können die in der Select-Klausel ausgewählten Werte auch in einen expliziten Typ umwandeln, der sich vom Typ der Bereichsvariablen unterscheidet. Diese Punkte werden im folgenden Code veranschaulicht.

Dim numbers1() As Integer = {1, 2, 4, 16, 32, 64}
Dim numbers2() As Double = {5.0#, 10.0#, 15.0#}

' This code does not result in an error.
Dim numberQuery1 = From n As Integer In numbers1 Where n > 5

' This code results in an error with Option Strict set to On. The type Double
' cannot be implicitly cast as type Integer.
Dim numberQuery2 = From n As Integer In numbers2 Where n > 5

' This code casts the values in the data source to type Integer. The type of
' the range variable is Integer.
Dim numberQuery3 = From n In numbers2.Cast(Of Integer)() Where n > 5

' This code returns the value of the range variable converted to Integer. The type of
' the range variable is Double.
Dim numberQuery4 = From n In numbers2 Where n > 5 Select CInt(n)

Abfragen, die vollständige Elemente der Quelldaten zurückgeben

Das folgende Beispiel zeigt einen LINQ-Abfragevorgang, der eine Sequenz von Elementen zurückgibt, die aus den Quelldaten ausgewählt wurden. Die Quelle (names) enthält ein Array von Zeichenfolgen, und die Abfrageausgabe ist eine Sequenz, die Zeichenfolgen enthält, die mit dem Buchstaben „M“ beginnen.

Dim names = {"John", "Rick", "Maggie", "Mary"}
Dim mNames = From name In names
             Where name.IndexOf("M") = 0
             Select name

For Each nm In mNames
    Console.WriteLine(nm)
Next

Dies entspricht dem folgenden Code, ist aber viel kürzer und einfacher zu schreiben. Die Abhängigkeit von lokalen Typrückschlüssen in Abfragen ist der bevorzugte Stil in Visual Basic.

Dim names2 = {"John", "Rick", "Maggie", "Mary"}
Dim mNames2 As IEnumerable(Of String) =
    From name As String In names
    Where name.IndexOf("M") = 0
    Select name

For Each nm As String In mNames
    Console.WriteLine(nm)
Next

Die folgenden Beziehungen sind in beiden vorherigen Codebeispielen vorhanden, unabhängig davon, ob die Typen implizit oder explizit bestimmt werden.

  1. Der Typ der Elemente in der Datenquelle (names) ist der Typ der Bereichsvariablen (name) in der Abfrage.

  2. Der Typ des Objekts, das ausgewählt ist (name), bestimmt den Typ der Abfragevariablen (mNames). Hier ist name eine Zeichenfolge, sodass die Abfragevariable IEnumerable(Of String) in Visual Basic ist.

  3. Die in mNames definierte Abfrage wird in der For Each-Schleife ausgeführt. Die Schleife durchläuft das Ergebnis der Abfrageausführung. Da mNames bei Ausführung eine Sequenz von Zeichenfolgen zurückgibt, ist die Schleifeniterationsvariable (nm) der Schleifen ebenfalls eine Zeichenfolge.

Abfragen, die ein Feld aus ausgewählten Elementen zurückgeben

Das folgende Beispiel zeigt einen LINQ to SQL-Abfragevorgang, der eine Sequenz zurückgibt, die nur einen Teil jedes aus der Datenquelle ausgewählten Elements enthält. Die Abfrage verwendet eine Auflistung von Customer-Objekten als Datenquelle und projiziert nur die Name-Eigenschaft im Ergebnis. Da der Kundenname eine Zeichenfolge ist, generiert die Abfrage eine Sequenz von Zeichenfolgen als Ausgabe.

' Method GetTable returns a table of Customer objects.
Dim customers = db.GetTable(Of Customer)()
Dim custNames = From cust In customers
                Where cust.City = "London"
                Select cust.Name

For Each custName In custNames
    Console.WriteLine(custName)
Next

Die Beziehungen zwischen Variablen ähneln denen im einfacheren Beispiel.

  1. Der Typ der Elemente in der Datenquelle (customers) ist der Typ der Bereichsvariablen (cust) in der Abfrage. In diesem Beispiel ist dieser Typ Customer.

  2. Die Select-Anweisung gibt die Name-Eigenschaft jedes Customer-Objekts anstelle des gesamten Objekts zurück. Da Name eine Zeichenfolge ist, lautet ist Abfragevariable (custNames) wieder IEnumerable(Of String), nicht von Customer.

  3. Da custNames eine Sequenz von Zeichenfolgen darstellt, muss die Iterationsvariable der For Each-Schleife (custName) auch vom Typ „string“ sein.

Ohne lokalen Typrückschluss wäre das vorherige Beispiel umständlicher zu schreiben und zu verstehen, wie das folgende Beispiel zeigt.

' Method GetTable returns a table of Customer objects.
 Dim customers As Table(Of Customer) = db.GetTable(Of Customer)()
 Dim custNames As IEnumerable(Of String) =
     From cust As Customer In customers
     Where cust.City = "London"
     Select cust.Name

 For Each custName As String In custNames
     Console.WriteLine(custName)
 Next

Abfragen, die anonyme Typen erfordern

Das folgende Beispiel zeigt eine komplexere Situation. Im vorherigen Beispiel war es unpraktisch, Typen für alle Variablen explizit anzugeben. In diesem Beispiel ist dies sogar unmöglich. Anstatt vollständige Customer-Elemente aus der Datenquelle oder ein einzelnes Feld aus jedem Element auszuwählen, gibt die Select-Klausel in dieser Abfrage zwei Eigenschaften des ursprünglichen Customer-Objekts zurück: Name und City. Als Reaktion auf die Select-Klausel definiert der Compiler einen anonymen Typ, der diese beiden Eigenschaften enthält. Das Ergebnis der Ausführung von nameCityQuery in der For Each-Schleife ist eine Sammlung von Instanzen des neuen anonymen Typs. Da der anonyme Typ keinen verwendbaren Namen aufweist, können Sie den Typ von nameCityQuery oder custInfo nicht explizit angeben. Das bedeutet, dass Sie bei einem anonymen Typ keinen Typnamen kennen, den Sie anstelle von String in IEnumerable(Of String) verwenden können. Weitere Informationen finden Sie unter Anonyme Typen.

' Method GetTable returns a table of Customer objects.
Dim customers = db.GetTable(Of Customer)()
Dim nameCityQuery = From cust In customers
                    Where cust.City = "London"
                    Select cust.Name, cust.City

For Each custInfo In nameCityQuery
    Console.WriteLine(custInfo.Name)
Next

Obwohl es nicht möglich ist, Typen für alle Variablen im vorherigen Beispiel anzugeben, bleiben die Beziehungen gleich.

  1. Der Typ der Elemente in der Datenquelle ist auch hier der Typ der Bereichsvariablen in der Abfrage. In diesem Codebeispiel ist cust eine Instanz von Customer.

  2. Da die Select-Anweisung einen anonymen generiert, muss die Abfragevariable (nameCityQuery) implizit als anonymer Typ typisiert werden. Ein anonymer Typ besitzt keinen verwendbaren Namen und kann daher nicht explizit angegeben werden.

  3. Der Typ der Iterationsvariablen in der For Each-Schleife ist der anonyme Typ, der in Schritt 2 erstellt wurde. Da der Typ keinen verwendbaren Namen aufweist, muss der Typ der Schleifeniterationsvariablen implizit bestimmt werden.

Weitere Informationen