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

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

Screenshot showing a pseudocode query with elements highlighted.

Тип переменной диапазона в запросе должен быть совместим с типом элементов в источнике данных. Тип переменной запроса должен быть совместим с элементом последовательности, определенным в предложении 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 метода. Значения, выбранные в 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содержит массив строк, а выходные данные запроса — это последовательность, содержащая строки, начинающиеся с буквы 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

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

' 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. Так как тип не имеет понятного имени, тип переменной итерации цикла должен быть определен неявно.

См. также