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).
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 On
wartość . 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 , names
zawiera 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.
Typ elementów w źródle danych,
names
, jest typem zmiennej zakresu,name
, w zapytaniu.Typ wybranego
name
obiektu określa typ zmiennej kwerendy .mNames
Otoname
ciąg, więc zmienna zapytania to IEnumerable(Of String) w Visual Basic.Zapytanie zdefiniowane w pliku
mNames
jest wykonywane wFor Each
pętli. Pętla iteruje wynik wykonywania zapytania. PonieważmNames
, gdy jest wykonywany, zwróci sekwencję ciągów, zmienną iteracji pętli ,nm
jest 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.
Typ elementów w źródle danych,
customers
, jest typem zmiennej zakresu,cust
, w zapytaniu. W tym przykładzie ten typ toCustomer
.Instrukcja
Select
zwracaName
właściwość każdegoCustomer
obiektu zamiast całego obiektu. PonieważName
jest to ciąg, zmienna kwerendy,custNames
, ponownie będzie IEnumerable(Of String), a nie .Customer
Ponieważ
custNames
reprezentuje sekwencję ciągów,For Each
zmienna iteracji pętli musicustName
być 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.
Typ elementów w źródle danych jest ponownie typem zmiennej zakresu w zapytaniu. W tym przykładzie
cust
jest wystąpieniemCustomer
klasy .Select
Ponieważ instrukcja generuje typ anonimowy, zmienna kwerendy musinameCityQuery
być niejawnie wpisywana jako typ anonimowy. Typ anonimowy nie ma nazwy użytecznej i dlatego nie można jawnie określić.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.