Compartilhar via


Relacionamentos de tipo em operações de consulta (Visual Basic)

As variáveis usadas em operações de consulta LINQ (consulta integrada à linguagem) são fortemente tipadas e devem ser compatíveis entre si. A tipagem 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, veja Operações Básicas de Consulta (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 cláusula Select. Por fim, o tipo de elementos de sequência também deve ser compatível com o tipo da variável de controle de loop usada na instrução For Each que executa a consulta. A tipagem forte facilita a identificação de erros de tipo no tempo de compilação.

O Visual Basic torna a tipagem forte conveniente implementando a inferência de tipo de variável local, também conhecida como tipagem implícita. Esse recurso é usado no exemplo anterior e será usado em todos os exemplos e documentação do LINQ. No Visual Basic, a inferência de tipo de variável local é realizada usando uma instrução Dim sem uma cláusula As. No exemplo a seguir, city é fortemente tipado como uma cadeia de caracteres.

Dim city = "Seattle"

Observação

A inferência de tipo de variável local funciona somente quando Option Infer é definido como On. Para obter mais informações, confira a Instrução Option Infer.

No entanto, mesmo que você use a inferência de tipo de variável local em uma consulta, as mesmas relações de tipo estã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 ao gravar consultas LINQ ou trabalhar com os exemplos de código e amostras 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. O tipo da variável de intervalo pode ser especificado usando uma cláusula As. No entanto, isso resultará em um erro se a conversão for uma conversão de estreitamento e Option Strict estiver definido como On. Portanto, recomendamos que você execute a conversão nos valores recuperados da fonte de dados. Os valores da fonte de dados podem ser convertidos para o tipo de variável de intervalo explícito usando o método Cast. Você também pode converter os valores selecionados na cláusula Select em um tipo explícito diferente do tipo da variável de intervalo. Esses pontos estã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 nos 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 gravar. A dependência da inferência de tipo de variável local em consultas é o estilo preferencial 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, sendo os tipos determinados implicitamente ou explicitamente.

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

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

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

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 que contém apenas uma parte de cada elemento selecionado na fonte de dados. A consulta utiliza uma coleção de objetos Customer como fonte de dados e projeta apenas a propriedade Name 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 de elementos na fonte de dados customers é o tipo da variável de intervalo cust na consulta. Neste exemplo, esse tipo é Customer.

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

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

Sem inferência de tipo de variável local, seria mais complicado gravar e entender o exemplo anterior, 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 Customer inteiros da fonte de dados ou um único campo de cada elemento, a cláusula Select nesta consulta retorna duas propriedades do objeto Customer original: Name e City. Em resposta à cláusula Select, o compilador define um tipo anônimo que contém essas duas propriedades. O resultado da execução de nameCityQuery no loop For Each é uma coleção de instâncias do novo tipo anônimo. Como o tipo anônimo não possui um nome utilizável, você não pode especificar o tipo nameCityQuery ou custInfo explicitamente. Ou seja, com um tipo anônimo, você não tem um nome de tipo para usar no lugar de String no 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 de 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 instrução Select produz um tipo anônimo, a variável de consulta nameCityQuery deve ser tipada implicitamente como um tipo anônimo. Um tipo anônimo não possui um nome utilizável e, portanto, não pode ser especificado explicitamente.

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

Confira também