Поделиться через


Отношения типов в операциях запроса (Visual Basic)

Переменные, используемые в операциях запроса LINQ, являются строго типизированными и должны быть совместимы друг с другом.Строгая типизация используется в источнике данных, в самом запросе и при выполнении запроса.На следующем рисунке показаны термины, используемые для описания запроса LINQ.Дополнительные сведения о частях запроса см. в разделе Основные операции запроса (Visual Basic).

Части запроса LINQ

Запрос символического кода с маркированными элементами.

Тип переменной диапазона в запросе должен быть совместим с типом элементов в источнике данных.Тип переменной запроса должен быть совместим с последовательностью элемента, определенной в предложении Select.И наконец, тип элементов последовательности также должен быть совместим с типом переменной цикла, которая используется в операторе For Each, выполняющем запрос.Строгая типизация упрощает идентификацию ошибок типов во время компиляции.

Visual Basic делает строгую типизацию удобной за счет реализации локального определения типа, также называемого неявной типизацией.Эта возможность используется в предыдущем примере, и применяется примерах и документации по LINQ.В Visual Basic локальное определение типа осуществляется при помощи оператора Dim без предложения As.В следующем примере city строго типизирован в качестве строки.

Dim city = "Seattle"
ПримечаниеПримечание

Локальное определение типа работает только тогда, когда Option Infer имеет значение On.Дополнительные сведения см. в разделе Оператор Option Infer.

Однако даже если локальное определение типа используется в запросе, отношение типов между переменными в источнике данных, переменной запрос и переменной цикла, выполняющего запрос, остается неизменным.При написании запросов LINQ или работе с примерами кода в документации знание отношений типов является полезным моментом.

Возможно, потребуется указать явный тип переменной диапазона, который не соответствует типу, возвращенному из источника данных.Тип переменной диапазона можно указать с помощью ключевого слова As.Однако это приведет к ошибке, если преобразование является сужающим, а параметр Option Strict имеет значение On.Поэтому рекомендуется применять преобразование к значениям, получаемым из источника данных.Значения из источника данных можно преобразовать к явно заданному типу переменной диапазона с помощью метода Cast<TResult>.Кроме того, можно приводить значения, выбранные в предложении Select, к явному типу, отличающемуся от типа переменной диапазона.Эти варианты демонстрируются в следующем коде.

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)

Запросы, которые возвращают целые элементы из источника данных

В следующем примере показана операция запроса LINQ, возвращающая последовательность элементов, выбранных из источника данных.Источник names содержит массив строк, а результат запроса представляет собой последовательность, содержащую строки, которые начинаются с буквы М.

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

Это аналогично следующему коду, но намного короче и проще в написании.Использование локального определения типов в запросах является предпочтительным для 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

Следующие отношения существуют в обоих предыдущих примерах кода независимо от способа определения типа — явного или неявного.

  1. Тип элементов в источнике данных — names — является типом переменной диапазона — name — в запросе.

  2. Тип объекта, который выбран, name, определяет тип переменной запроса mNames.Здесь name является строкой, поэтому переменная запроса имеет тип IEnumerable(Of String) в Visual Basic.

  3. Запрос, определенный в mNames, выполняется в цикле For Each.Цикл выполняет итерацию результата выполнения запроса.Поскольку mNames при выполнении вернет последовательность строк, переменная итерации цикла nm также является строкой.

Запросы, возвращающие одно поле из выбранных элементов

В следующем примере показана операция запроса LINQ to SQL, которая возвращает последовательность, содержащую только одну часть каждого элемента, выбранного из источника данных.Запрос получает коллекцию объектов Customer в качестве источника данных, а в результате проецирует только свойство Name.Поскольку имя заказчика является строкой, запрос создает последовательность строк в качестве выходных данных.

' 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

Отношения между переменными такие же, как и в более простых примерах.

  1. Тип элементов в источнике данных, customers, всегда является типом переменной диапазона, cust, в запросе.В этом примере этот тип является Customer.

  2. Оператор Select возвращает свойство Name каждого объекта вместо целого объекта Customer.Поскольку Name является строкой, переменная запроса custNames снова будет иметь тип IEnumerable(Of String), а не Customer.

  3. Поскольку custNames представляет собой последовательность строк, переменная итерации цикла For Each, custName должна быть строкой.

Без локального определения типа предыдущий пример был бы более громоздким для записи и понимания, как показано в следующем примере.

' 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

Запросы, требующие анонимные типы

В следующем примере показана более сложная ситуация.В предыдущем примере явное указание типов для всех переменных было неудобным.В данном примере это невозможно.В отличие от выбора полных элементов Customer из источника данных или одного поля из каждого элемента, предложение Select в этом запросе возвращает два свойства из исходного объекта Customer: Name и City.В ответ на предложение Select компилятор определяет анонимный тип, содержащий эти два свойства.Результатом выполнения nameCityQuery в цикле For Each является коллекция экземпляров нового анонимного типа.Поскольку анонимный тип не имеет имени, нельзя указать тип для nameCityQuery или custInfo явным образом.Это значит, что при наличии анонимного типа отсутствует имя типа, которое можно использовать вместо String в IEnumerable(Of String).Дополнительные сведения см. в разделе Анонимные типы (Visual Basic).

' 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

Хотя указать типы для всех переменных в предыдущем примере невозможно, отношения между ними остаются неизменными.

  1. Тип элементов в источнике данных является типом переменной диапазона в запросе.В этом примере cust представляет собой экземпляр Customer.

  2. Так как оператор Select создает анонимный тип, переменная запроса nameCityQuery должна быть неявно типизирована в качестве анонимного типа.Анонимный тип не имеет имени и поэтому не может быть указан явно.

  3. Типом переменной перебора в цикле For Each является анонимный тип, созданный на шаге 2.Поскольку у типа нет пригодного для использования имени, тип переменной перебора цикла следует определять неявно.

См. также

Основные понятия

Анонимные типы (Visual Basic)

Вывод локального типа (Visual Basic)

Знакомство с LINQ в Visual Basic

Другие ресурсы

Приступая к работе с LINQ в Visual Basic

LINQ в Visual Basic

Запросы (Visual Basic)