🎯 Objetivo: Neste capítulo, você irá dominar o LINQ (Language-Integrated Query), uma das funcionalidades mais poderosas e elegantes do C#. LINQ permite que você escreva consultas a dados de forma unificada e segura, independentemente da fonte de dados, seja uma coleção em memória, um banco de dados, ou um arquivo XML.


🤔 O Problema Antes do LINQ

Imagine que seu programa precisa fazer o seguinte:

  1. Encontrar todos os produtos com preço acima de R$ 500 em uma lista de objetos.
  2. Consultar todos os clientes de "São Paulo" em um banco de dados SQL.
  3. Obter todos os posts de um arquivo XML com a tag <featured>.

Antes do LINQ, você precisaria de três abordagens diferentes:

Essa inconsistência tornava o código difícil de ler, manter e propício a erros.


✨ A Solução LINQ

LINQ é uma sintaxe de consulta unificada que se integra diretamente à linguagem C#. Ela resolve o problema de forma elegante, permitindo que você use a mesma sintaxe para consultar qualquer tipo de fonte de dados, desde que haja um Provider (provedor) LINQ para ela.

O grande benefício é a segurança de tipos e a inteligência da IDE. Se você cometer um erro de sintaxe ou de nome de atributo na sua consulta LINQ, o compilador C# irá avisá-lo imediatamente, antes mesmo de você executar o programa.

📋 As Duas Sintaxes do LINQ

Existem duas formas de escrever consultas LINQ. Ambas fazem a mesma coisa, mas uma pode ser mais legível que a outra, dependendo da sua preferência.

  1. Sintaxe de Consulta (Query Syntax): É a sintaxe mais parecida com SQL, ideal para consultas mais simples e declarativas.

    var resultado = from produto in listaDeProdutos
                    where produto.Preco > 500
                    select produto;
    
  2. Sintaxe de Método (Method Syntax): É a sintaxe mais comum e flexível, que usa métodos de extensão e expressões lambda.

    var resultado = listaDeProdutos.Where(produto => produto.Preco > 500);
    

Por baixo dos panos, o compilador C# converte a Sintaxe de Consulta para a Sintaxe de Método.


🧪 Exemplo Prático: LINQ a Objetos

Vamos usar uma lista de produtos para ver o LINQ em ação.

// 1. Nossa fonte de dados: uma lista de objetos em memória
public class Produto
{
    public int Id { get; set; }
    public string Nome { get; set; }
    public decimal Preco { get; set; }
    public string Categoria { get; set; }
}

public class ExemploLinq
{
    public static void Main(string[] args)
    {
        var produtos = new List<Produto>
        {
            new Produto { Id = 1, Nome = "Mouse", Preco = 120.00m, Categoria = "Periféricos" },
            new Produto { Id = 2, Nome = "Teclado", Preco = 650.00m, Categoria = "Periféricos" },
            new Produto { Id = 3, Nome = "Monitor", Preco = 1200.00m, Categoria = "Hardware" },
            new Produto { Id = 4, Nome = "Webcam", Preco = 300.00m, Categoria = "Acessórios" },
            new Produto { Id = 5, Nome = "SSD 1TB", Preco = 450.00m, Categoria = "Hardware" }
        };

        Console.WriteLine("--- Produtos com preço acima de R$500.00 ---");

        // 2. Filtrando (where)
        // Sintaxe de Consulta
        var produtosCarosQuery = from p in produtos
                                 where p.Preco > 500
                                 select p;

        // Sintaxe de Método
        var produtosCarosMethod = produtos.Where(p => p.Preco > 500);

        foreach (var p in produtosCarosMethod)
        {
            Console.WriteLine($"- {p.Nome} | R${p.Preco}");
        }

        Console.WriteLine("\n--- Nomes de produtos ordenados alfabeticamente ---");

        // 3. Ordenando (orderby) e Projetando (select)
        // Sintaxe de Consulta
        var nomesOrdenadosQuery = from p in produtos
                                  orderby p.Nome
                                  select p.Nome;

        // Sintaxe de Método
        var nomesOrdenadosMethod = produtos.OrderBy(p => p.Nome).Select(p => p.Nome);

        foreach (var nome in nomesOrdenadosMethod)
        {
            Console.WriteLine($"- {nome}");
        }

        Console.WriteLine("\n--- Produtos do tipo 'Hardware' ordenados por preço ---");

        // 4. Combinando operações
        // Sintaxe de Consulta
        var hardwarePorPrecoQuery = from p in produtos
                                    where p.Categoria == "Hardware"
                                    orderby p.Preco descending
                                    select p;

        // Sintaxe de Método
        var hardwarePorPrecoMethod = produtos
                                     .Where(p => p.Categoria == "Hardware")
                                     .OrderByDescending(p => p.Preco);

        foreach (var p in hardwarePorPrecoMethod)
        {
            Console.WriteLine($"- {p.Nome} | R${p.Preco}");
        }
    }
}