Digite relações em operações de consulta (Visual Basic)

As variáveis usadas em operações de consulta LINQ (Language-Integrated Query) são fortemente tipadas e devem ser compatíveis entre si. A digitação forte é usada na fonte de dados, na própria consulta e na execução da consulta. A ilustração a seguir identifica os termos usados para descrever uma consulta LINQ. Para obter mais informações sobre as partes de uma consulta, consulte Operações de consulta básicas (Visual Basic).

Screenshot showing a pseudocode query with elements highlighted.

O tipo da variável de intervalo na consulta deve ser compatível com o tipo dos elementos na fonte de dados. O tipo da variável de consulta deve ser compatível com o elemento de sequência definido na Select cláusula. Finalmente, o tipo dos elementos de sequência também deve ser compatível com o tipo da variável de controle de loop que é usada na For Each instrução que executa a consulta. Essa digitação forte facilita a identificação de erros de tipo em tempo de compilação.

O Visual Basic torna a digitação forte conveniente implementando a inferência de tipo local, também conhecida como digitação implícita. Esse recurso é usado no exemplo anterior e você o verá usado em todas as amostras e documentação do LINQ. No Visual Basic, a inferência de tipo local é realizada simplesmente usando uma Dim instrução sem uma As cláusula. No exemplo a seguir, city é fortemente tipado como uma cadeia de caracteres.

Dim city = "Seattle"

Nota

A inferência de tipo local funciona somente quando Option Infer é definida como On. Para obter mais informações, consulte Option Infer Statement.

No entanto, mesmo se você usar a inferência de tipo local em uma consulta, as mesmas relações de tipo estarão presentes entre as variáveis na fonte de dados, na variável de consulta e no loop de execução da consulta. É útil ter uma compreensão básica dessas relações de tipo quando você estiver escrevendo consultas LINQ ou trabalhando com os exemplos e exemplos de código na documentação.

Talvez seja necessário especificar um tipo explícito para uma variável de intervalo que não corresponda ao tipo retornado da fonte de dados. Você pode especificar o tipo da variável range usando uma As cláusula. No entanto, isso resulta em um erro se a conversão for uma conversão de estreitamento e Option Strict estiver definida como On. Portanto, recomendamos que você execute a conversão nos valores recuperados da fonte de dados. Você pode converter os valores da fonte de dados para o tipo de variável de intervalo explícito usando o Cast método. Você também pode converter os valores selecionados na Select cláusula para um tipo explícito que é diferente do tipo da variável de intervalo. Estes pontos são ilustrados no código a seguir.

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)

Consultas que retornam elementos inteiros dos dados de origem

O exemplo a seguir mostra uma operação de consulta LINQ que retorna uma sequência de elementos selecionados dos dados de origem. A origem, names, contém uma matriz de cadeias de caracteres, e a saída da consulta é uma sequência que contém cadeias de caracteres que começam com a letra 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

Isso é equivalente ao código a seguir, mas é muito mais curto e fácil de escrever. A confiança na inferência de tipo local em consultas é o estilo preferido no 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

As relações a seguir existem em ambos os exemplos de código anteriores, quer os tipos sejam determinados implícita ou explicitamente.

  1. O tipo dos elementos na fonte de dados, names, é o tipo da variável de intervalo, name, na consulta.

  2. O tipo do objeto selecionado, name, determina o tipo da variável de consulta, mNames. Aqui name está uma cadeia de caracteres, portanto, a variável de consulta é IEnumerable(Of String) no Visual Basic.

  3. A consulta definida em mNames é executada For Each no loop. O loop itera sobre o resultado da execução da consulta. Como mNames, quando é executado, retornará uma sequência de strings, a variável de iteração de loop, nm, também é uma string.

Consultas que retornam um campo de elementos selecionados

O exemplo a seguir mostra uma operação de consulta LINQ to SQL que retorna uma sequência contendo apenas uma parte de cada elemento selecionado da fonte de dados. A consulta usa uma coleção de objetos como sua fonte de Customer dados e projeta apenas a Name propriedade no resultado. Como o nome do cliente é uma cadeia de caracteres, a consulta produz uma sequência de cadeias de caracteres como saída.

' 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

As relações entre variáveis são como as do exemplo mais simples.

  1. O tipo dos elementos na fonte de dados, customers, é o tipo da variável de intervalo, cust, na consulta. Neste exemplo, esse tipo é Customer.

  2. A Select instrução retorna a Name propriedade de cada Customer objeto em vez do objeto inteiro. Como Name é uma cadeia de caracteres, a variável de consulta, custNames, será novamente IEnumerable(Of String), não de Customer.

  3. Como custNames representa uma sequência de cadeias de caracteres, a For Each variável de iteração do loop, custName, deve ser uma cadeia de caracteres.

Sem inferência de tipo local, o exemplo anterior seria mais complicado de escrever e entender, como mostra o exemplo a seguir.

' 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

Consultas que exigem tipos anônimos

O exemplo a seguir mostra uma situação mais complexa. No exemplo anterior, era inconveniente especificar tipos para todas as variáveis explicitamente. Neste exemplo, é impossível. Em vez de selecionar elementos inteiros Customer da fonte de dados ou um único campo de cada elemento, a Select cláusula nesta consulta retorna duas propriedades do objeto original Customer : Name e City. Em resposta à Select cláusula, o compilador define um tipo anônimo que contém essas duas propriedades. O resultado da execução nameCityQuery no For Each loop é uma coleção de instâncias do novo tipo anônimo. Como o tipo anônimo não tem nome utilizável, não é possível especificar o tipo de nameCityQuery ou custInfo explicitamente. Ou seja, com um tipo anônimo, você não tem nenhum nome de tipo para usar no lugar de String em IEnumerable(Of String). Para obter mais informações, consulte Tipos anônimos.

' 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

Embora não seja possível especificar tipos para todas as variáveis no exemplo anterior, as relações permanecem as mesmas.

  1. O tipo dos elementos na fonte de dados é novamente o tipo da variável de intervalo na consulta. Neste exemplo, cust é uma instância de Customer.

  2. Como a Select instrução produz um tipo anônimo, a variável de consulta, nameCityQuery, deve ser implicitamente digitada como um tipo anônimo. Um tipo anônimo não tem nome utilizável e, portanto, não pode ser especificado explicitamente.

  3. O tipo da variável de iteração no For Each loop é o tipo anônimo criado na etapa 2. Como o tipo não tem nome utilizável, o tipo da variável de iteração de loop deve ser determinado implicitamente.

Consulte também