Compartilhar via


Relações de tipo em operações de consulta LINQ (C#)

Para redigir consultas de maneira eficaz, você deve entender como os tipos das variáveis em uma operação completa de consulta se relacionam entre si. Se você entender essas relações, compreenderá com mais facilidade os exemplos de linq e exemplos de código na documentação. Além disso, você entenderá o que ocorre quando as variáveis são digitada implicitamente usando var.

As operações de consulta LINQ são fortemente tipadas na fonte de dados, na própria consulta e na execução da consulta. O tipo das variáveis na consulta deve ser compatível com o tipo dos elementos na fonte de dados e com o tipo da variável de iteração na foreach instrução. Essa digitação forte garante que os erros de tipo sejam capturados no momento da compilação, quando eles podem ser corrigidos antes que os usuários os encontrem.

Para demonstrar essas relações de tipo, a maioria dos exemplos a seguir usam digitação explícita para todas as variáveis. O último exemplo mostra como os mesmos princípios se aplicam mesmo quando você usa digitação implícita usando var.

Consultas que não transformam os dados de origem

A ilustração a seguir mostra uma operação de consulta LINQ to Objects que não executa transformações nos dados. A origem contém uma sequência de cadeias de caracteres e a saída da consulta também é uma sequência de cadeias de caracteres.

Diagrama que mostra a relação de tipos de dados em uma consulta LINQ.

  1. O argumento de tipo da fonte de dados determina o tipo da variável de intervalo.
  2. O tipo do objeto selecionado determina o tipo da variável de consulta. Aqui name está uma cadeia de caracteres. Portanto, a variável de consulta é um IEnumerable<string>.
  3. A variável de consulta é iterada na instrução foreach. Como a variável de consulta é uma sequência de cadeias de caracteres, a variável de iteração também é uma cadeia de caracteres.

Consultas que transformam os dados de origem

A ilustração a seguir mostra uma operação de consulta LINQ to SQL que executa uma transformação simples nos dados. A consulta usa uma sequência de Customer objetos como entrada e seleciona apenas a Name propriedade no resultado. Como Name é uma cadeia de caracteres, a consulta produz uma sequência de cadeias de caracteres como saída.

Diagrama mostrando uma consulta que transforma o tipo de dados.

  1. O argumento de tipo da fonte de dados determina o tipo da variável de intervalo.
  2. A select instrução retorna a Name propriedade em vez do objeto completo Customer . Como Name é uma cadeia de caracteres, o argumento de custNameQuery tipo é string, não Customer.
  3. Como custNameQuery é uma sequência de cadeias de caracteres, a foreach variável de iteração do loop também deve ser um string.

A ilustração a seguir mostra uma transformação um pouco mais complexa. A select instrução retorna um tipo anônimo que captura apenas dois membros do objeto original Customer .

Diagrama mostrando uma consulta mais complexa que transforma o tipo de dados.

  1. O argumento de tipo da fonte de dados é sempre o tipo da variável de intervalo na consulta.
  2. Como a select instrução produz um tipo anônimo, a variável de consulta deve ser digitada implicitamente usando var.
  3. Como o tipo da variável de consulta está implícito, a variável de iteração no foreach loop também deve estar implícita.

Permitindo que o compilador infera informações de tipo

Embora você deva entender as relações de tipo em uma operação de consulta, você tem a opção de permitir que o compilador faça todo o trabalho para você. A palavra-chave var pode ser usada para qualquer variável local em uma operação de consulta. A ilustração a seguir é semelhante ao exemplo número 2 que foi discutido anteriormente. No entanto, o compilador fornece o tipo forte para cada variável na operação de consulta.

Diagrama que mostra o fluxo de tipo com tipagem implícita.

LINQ e tipos genéricos (C#)

As consultas LINQ são baseadas em tipos genéricos. Você não precisa de um conhecimento aprofundado de genéricos antes de começar a escrever consultas. No entanto, talvez você queira entender dois conceitos básicos:

  1. Ao criar uma instância de uma classe de coleção genérica, como List<T>, você substitui o "T" pelo tipo de objetos que a lista conterá. Por exemplo, uma lista de cadeias de caracteres é expressa como List<string>, e uma lista de Customer objetos é expressa como List<Customer>. Uma lista genérica é fortemente tipada e oferece muitos benefícios em coleções que armazenam seus elementos como Object. Se você tentar adicionar um Customer a um List<string>, receberá um erro em tempo de compilação. É fácil usar coleções genéricas, porque você não precisa realizar a conversão de tipo em tempo de execução.
  2. IEnumerable<T> é a interface que permite que classes de coleção genéricas sejam enumeradas usando a foreach instrução. Classes de coleção genérica dão suporte a IEnumerable<T> assim como classes de coleção não genéricas, como ArrayList dão suporte a IEnumerable.

Para obter mais informações sobre genéricos, consulte Genéricos.

Variáveis IEnumerable<T> em consultas LINQ

As variáveis de consulta LINQ são digitada como IEnumerable<T> ou um tipo derivado, como IQueryable<T>. Quando você vê uma variável de consulta que é digitada como IEnumerable<Customer>, isso significa apenas que a consulta, quando executada, produzirá uma sequência de zero ou mais Customer objetos.

IEnumerable<Customer> customerQuery = from cust in customers
                                      where cust.City == "London"
                                      select cust;

foreach (Customer customer in customerQuery)
{
    Console.WriteLine($"{customer.LastName}, {customer.FirstName}");
}

Permitir que o compilador manipule declarações de tipo genérico

Se preferir, você poderá evitar a sintaxe genérica usando a palavra-chave var . A var palavra-chave instrui o compilador a inferir o tipo de uma variável de consulta examinando a fonte de dados especificada na from cláusula. O exemplo a seguir produz o mesmo código compilado do exemplo anterior:

var customerQuery2 = from cust in customers
                     where cust.City == "London"
                     select cust;

foreach(var customer in customerQuery2)
{
    Console.WriteLine($"{customer.LastName}, {customer.FirstName}");
}

A var palavra-chave é útil quando o tipo da variável é óbvio ou quando não é tão importante especificar explicitamente tipos genéricos aninhados, como aqueles produzidos por consultas de grupo. Em geral, recomendamos que, se você usar var, perceba que ele pode tornar seu código mais difícil para outras pessoas lerem. Para obter mais informações, consulte Variáveis locais de tipo implícito.