Udostępnij za pośrednictwem


Relacje typu w operacjach zapytań (Visual Basic)

Zmienne używane w operacjach zapytań zintegrowanych z językiem (LINQ) są silnie typizowane i muszą być ze sobą zgodne. Silne wpisywanie jest używane w źródle danych, w samym zapytaniu i w wykonaniu zapytania. Poniższa ilustracja identyfikuje terminy używane do opisywania zapytania LINQ. Aby uzyskać więcej informacji na temat części zapytania, zobacz Podstawowe operacje zapytań (Visual Basic).

Screenshot showing a pseudocode query with elements highlighted.

Typ zmiennej zakresu w zapytaniu musi być zgodny z typem elementów w źródle danych. Typ zmiennej kwerendy musi być zgodny z elementem sekwencji zdefiniowanym w klauzuli Select . Na koniec typ elementów sekwencji musi być również zgodny z typem zmiennej sterującej pętli, która jest używana w For Each instrukcji wykonującej zapytanie. To silne wpisywanie ułatwia identyfikację błędów typu w czasie kompilacji.

Język Visual Basic sprawia, że silne wpisywanie jest wygodne, implementując wnioskowanie typu lokalnego, znane również jako niejawne wpisywanie. Ta funkcja jest używana w poprzednim przykładzie i zobaczysz, że jest używana w przykładach LINQ i dokumentacji. W języku Visual Basic wnioskowanie typu lokalnego odbywa się po prostu przy użyciu Dim instrukcji bez klauzuli As . W poniższym przykładzie city jest silnie typizowane jako ciąg.

Dim city = "Seattle"

Uwaga

Wnioskowanie typu lokalnego działa tylko wtedy, gdy Option Infer jest ustawiona wartość On. Aby uzyskać więcej informacji, zobacz Option Infer Statement (Instrukcja wnioskowania opcji).

Jednak nawet jeśli używasz wnioskowania typu lokalnego w zapytaniu, relacje tego samego typu są obecne wśród zmiennych w źródle danych, zmiennej zapytania i pętli wykonywania zapytania. Warto mieć podstawową wiedzę na temat tych relacji typów podczas pisania zapytań LINQ lub pracy z przykładami przykładów i kodu w dokumentacji.

Może być konieczne określenie jawnego typu zmiennej zakresu, która nie jest zgodna z typem zwracanym ze źródła danych. Typ zmiennej zakresu można określić przy użyciu klauzuli As . Jednak powoduje to błąd, jeśli konwersja jest konwersją zawężającą i Option Strict jest ustawiona na Onwartość . W związku z tym zalecamy przeprowadzenie konwersji wartości pobranych ze źródła danych. Wartości ze źródła danych można przekonwertować na jawny typ zmiennej zakresu przy użyciu Cast metody . Można również rzutować wartości wybrane w klauzuli Select na jawny typ, który różni się od typu zmiennej zakresu. Te punkty przedstawiono w poniższym kodzie.

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)

Zapytania zwracające całe elementy danych źródłowych

Poniższy przykład przedstawia operację zapytania LINQ zwracającą sekwencję elementów wybranych z danych źródłowych. Źródło , nameszawiera tablicę ciągów, a dane wyjściowe zapytania to sekwencja zawierająca ciągi rozpoczynające się literą M.

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

Jest to odpowiednik następującego kodu, ale jest znacznie krótszy i łatwiejszy do pisania. Poleganie na wnioskowaniu typu lokalnego w zapytaniach jest preferowanym stylem w języku 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

W obu poprzednich przykładach kodu istnieją następujące relacje, niezależnie od tego, czy typy są określane niejawnie, czy jawnie.

  1. Typ elementów w źródle danych, names, jest typem zmiennej zakresu, name, w zapytaniu.

  2. Typ wybranego nameobiektu określa typ zmiennej kwerendy . mNames Oto name ciąg, więc zmienna zapytania to IEnumerable(Of String) w Visual Basic.

  3. Zapytanie zdefiniowane w pliku mNames jest wykonywane w For Each pętli. Pętla iteruje wynik wykonywania zapytania. Ponieważ mNames, gdy jest wykonywany, zwróci sekwencję ciągów, zmienną iteracji pętli , nmjest również ciągiem.

Zapytania zwracające jedno pole z wybranych elementów

Poniższy przykład przedstawia operację zapytania LINQ to SQL, która zwraca sekwencję zawierającą tylko jedną część każdego elementu wybranego ze źródła danych. Zapytanie przyjmuje kolekcję Customer obiektów jako źródło danych i projektuje tylko Name właściwość w wyniku. Ponieważ nazwa klienta jest ciągiem, zapytanie tworzy sekwencję ciągów jako dane wyjściowe.

' 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

Relacje między zmiennymi są podobne do tych w prostszym przykładzie.

  1. Typ elementów w źródle danych, customers, jest typem zmiennej zakresu, cust, w zapytaniu. W tym przykładzie ten typ to Customer.

  2. Instrukcja Select zwraca Name właściwość każdego Customer obiektu zamiast całego obiektu. Ponieważ Name jest to ciąg, zmienna kwerendy, custNames, ponownie będzie IEnumerable(Of String), a nie .Customer

  3. Ponieważ custNames reprezentuje sekwencję ciągów, For Each zmienna iteracji pętli musi custNamebyć ciągiem.

Bez wnioskowania typu lokalnego poprzedni przykład byłby bardziej uciążliwy do zapisu i zrozumienia, jak pokazano w poniższym przykładzie.

' 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

Zapytania wymagające typów anonimowych

W poniższym przykładzie przedstawiono bardziej złożoną sytuację. W poprzednim przykładzie było niewygodne określenie typów dla wszystkich zmiennych jawnie. W tym przykładzie jest to niemożliwe. Zamiast wybierać całe Customer elementy ze źródła danych lub pojedynczego pola z każdego elementu, klauzula Select w tym zapytaniu zwraca dwie właściwości oryginalnego Customer obiektu: Name i City. W odpowiedzi na klauzulę Select kompilator definiuje typ anonimowy zawierający te dwie właściwości. Wynikiem wykonywania nameCityQuery w For Each pętli jest kolekcja wystąpień nowego typu anonimowego. Ponieważ typ anonimowy nie ma użytecznej nazwy, nie można określić typu nameCityQuery ani custInfo jawnie. Oznacza to, że w przypadku typu anonimowego nie ma nazwy typu, która ma być używana zamiast String w IEnumerable(Of String)pliku . Aby uzyskać więcej informacji, zobacz Typy anonimowe.

' 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

Chociaż nie można określić typów dla wszystkich zmiennych w poprzednim przykładzie, relacje pozostają takie same.

  1. Typ elementów w źródle danych jest ponownie typem zmiennej zakresu w zapytaniu. W tym przykładzie cust jest wystąpieniem Customerklasy .

  2. Select Ponieważ instrukcja generuje typ anonimowy, zmienna kwerendy musi nameCityQuerybyć niejawnie wpisywana jako typ anonimowy. Typ anonimowy nie ma nazwy użytecznej i dlatego nie można jawnie określić.

  3. Typ zmiennej iteracji w For Each pętli jest typem anonimowym utworzonym w kroku 2. Ponieważ typ nie ma użytecznej nazwy, typ zmiennej iteracji pętli musi być określany niejawnie.

Zobacz też