
LINQ Methods: O Guia Completo com Exemplos Práticos
LINQ (Language Integrated Query) é uma das funcionalidades mais poderosas do C#. Introduzido no .NET 3.5, ele traz para dentro da linguagem uma sintaxe expressiva para consultar, filtrar e transformar coleções de dados — seja uma lista em memória, um banco de dados, um XML ou qualquer fonte que implemente IEnumerable<T> ou IQueryable<T>.
Em vez de escrever loops foreach repetitivos com condicionais aninhadas, o LINQ permite expressar a intenção da operação de forma legível e declarativa:
// Sem LINQ
var resultado = new List<string>();
foreach (var nome in nomes)
{
if (nome.StartsWith("A"))
resultado.Add(nome);
}
// Com LINQ
var resultado = nomes.Where(n => n.StartsWith("A"));
Os métodos LINQ são extension methods definidos em System.Linq e se organizam em categorias bem definidas. Este artigo cobre todas elas.

1. Filtering (Filtragem)
Métodos que retornam um subconjunto da coleção com base em uma condição.
var numeros = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Where
Filtra elementos que satisfazem um predicado.
var pares = numeros.Where(n => n % 2 == 0);
| Entrada | Saída |
|---|---|
| 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 | 2, 4, 6, 8, 10 |
Take
Retorna os primeiros N elementos.
var primeiros3 = numeros.Take(3);
| Entrada | N | Saída |
|---|---|---|
| 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 | 3 | 1, 2, 3 |
Skip
Ignora os primeiros N elementos e retorna o restante.
var semOs3Primeiros = numeros.Skip(3);
| Entrada | N | Saída |
|---|---|---|
| 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 | 3 | 4, 5, 6, 7, 8, 9, 10 |
TakeWhile
Retorna elementos enquanto a condição for verdadeira, parando ao encontrar o primeiro que falha.
var enquantoMenorQue5 = numeros.TakeWhile(n => n < 5);
| Entrada | Condição | Saída |
|---|---|---|
| 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 | n < 5 | 1, 2, 3, 4 |
SkipWhile
Ignora elementos enquanto a condição for verdadeira, retornando o restante a partir do primeiro que falha.
var aPartirDo5 = numeros.SkipWhile(n => n < 5);
| Entrada | Condição | Saída |
|---|---|---|
| 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 | n < 5 | 5, 6, 7, 8, 9, 10 |
2. Projecting (Projeção)
Métodos que transformam cada elemento em outro formato.
var produtos = new List<(string Nome, double Preco)>
{
("Notebook", 3500.0),
("Mouse", 120.0),
("Teclado", 250.0)
};
Select
Projeta cada elemento em um novo formato.
var nomes = produtos.Select(p => p.Nome);
| Entrada | Saída |
|---|---|
| (Notebook, 3500), (Mouse, 120), (Teclado, 250) | "Notebook", "Mouse", "Teclado" |
SelectMany
Achata coleções aninhadas em uma única sequência.
var pedidos = new List<List<string>>
{
new() { "Notebook", "Mouse" },
new() { "Teclado", "Monitor" }
};
var todosItens = pedidos.SelectMany(p => p);
| Entrada | Saída |
|---|---|
| ["Notebook","Mouse"], ["Teclado","Monitor"] | "Notebook", "Mouse", "Teclado", "Monitor" |
3. Joining (Junção)
Métodos para combinar duas coleções com base em uma chave comum.
var clientes = new List<(int Id, string Nome)>
{
(1, "Alice"),
(2, "Bruno"),
(3, "Carol")
};
var pedidos = new List<(int ClienteId, string Produto)>
{
(1, "Notebook"),
(2, "Mouse"),
(1, "Teclado")
};
Join
Une duas coleções por uma chave, retornando pares correspondentes (como INNER JOIN no SQL).
var resultado = clientes.Join(
pedidos,
c => c.Id,
p => p.ClienteId,
(c, p) => $"{c.Nome} comprou {p.Produto}"
);
| Cliente | Pedido | Saída |
|---|---|---|
| (1, Alice), (2, Bruno), (3, Carol) | (1, Notebook), (2, Mouse), (1, Teclado) | "Alice comprou Notebook", "Bruno comprou Mouse", "Alice comprou Teclado" |
GroupJoin
Une duas coleções por chave, retornando cada elemento da esquerda com sua coleção de correspondências (como LEFT JOIN no SQL).
var resultado = clientes.GroupJoin(
pedidos,
c => c.Id,
p => p.ClienteId,
(c, ps) => $"{c.Nome}: {string.Join(", ", ps.Select(p => p.Produto))}"
);
| Saída |
|---|
| "Alice: Notebook, Teclado" |
| "Bruno: Mouse" |
| "Carol: " |
Zip
Combina duas sequências elemento a elemento, como um zíper.
var letras = new List<string> { "A", "B", "C" };
var numeros = new List<int> { 1, 2, 3 };
var combinados = letras.Zip(numeros, (l, n) => $"{l}{n}");
| Entrada 1 | Entrada 2 | Saída |
|---|---|---|
| "A", "B", "C" | 1, 2, 3 | "A1", "B2", "C3" |
4. Ordering (Ordenação)
Métodos para ordenar elementos.
var pessoas = new List<(string Nome, int Idade)>
{
("Carlos", 30),
("Ana", 25),
("Bruno", 30),
("Diana", 25)
};
OrderBy / OrderByDescending
Ordena a coleção por uma chave, em ordem crescente ou decrescente.
var porIdade = pessoas.OrderBy(p => p.Idade);
var porIdadeDesc = pessoas.OrderByDescending(p => p.Idade);
| Entrada | OrderBy(Idade) | OrderByDescending(Idade) |
|---|---|---|
| Carlos(30), Ana(25), Bruno(30), Diana(25) | Ana(25), Diana(25), Carlos(30), Bruno(30) | Carlos(30), Bruno(30), Ana(25), Diana(25) |
ThenBy / ThenByDescending
Critério de ordenação secundário, aplicado após OrderBy.
var ordenado = pessoas
.OrderBy(p => p.Idade)
.ThenBy(p => p.Nome);
| Saída |
|---|
| Ana(25), Diana(25), Bruno(30), Carlos(30) |
Reverse
Inverte a ordem atual da sequência.
var numeros = new List<int> { 1, 2, 3, 4, 5 };
var invertido = numeros.Reverse();
| Entrada | Saída |
|---|---|
| 1, 2, 3, 4, 5 | 5, 4, 3, 2, 1 |
5. Grouping (Agrupamento)
GroupBy
Agrupa elementos por uma chave, retornando coleções nomeadas.
var funcionarios = new List<(string Nome, string Depto)>
{
("Alice", "TI"),
("Bruno", "RH"),
("Carol", "TI"),
("Diego", "RH"),
("Eva", "TI")
};
var grupos = funcionarios.GroupBy(f => f.Depto);
foreach (var grupo in grupos)
Console.WriteLine($"{grupo.Key}: {string.Join(", ", grupo.Select(f => f.Nome))}");
| Entrada | Saída |
|---|---|
| Alice(TI), Bruno(RH), Carol(TI), Diego(RH), Eva(TI) | TI → Alice, Carol, Eva / RH → Bruno, Diego |
6. Conversion (Conversão)
Métodos para converter a sequência para outro tipo de coleção.
IEnumerable<string> nomes = new[] { "Ana", "Bruno", "Carol" };
ToArray
Converte para array T[].
string[] array = nomes.ToArray();
ToList
Converte para List<T>.
List<string> lista = nomes.ToList();
ToDictionary
Converte para Dictionary<TKey, TValue>.
var produtos = new List<(int Id, string Nome)>
{
(1, "Notebook"), (2, "Mouse"), (3, "Teclado")
};
Dictionary<int, string> dict = produtos.ToDictionary(p => p.Id, p => p.Nome);
| Entrada | Saída |
|---|---|
| (1,Notebook), (2,Mouse), (3,Teclado) | {1:"Notebook", 2:"Mouse", 3:"Teclado"} |
ToLookup
Como ToDictionary, mas permite múltiplos valores por chave (ILookup<TKey, TElement>).
var vendas = new List<(string Vendedor, string Produto)>
{
("Alice", "Notebook"),
("Bruno", "Mouse"),
("Alice", "Teclado")
};
ILookup<string, string> lookup = vendas.ToLookup(v => v.Vendedor, v => v.Produto);
// lookup["Alice"] → ["Notebook", "Teclado"]
AsEnumerable
Força a avaliação como IEnumerable<T> — útil para sair do contexto IQueryable (Entity Framework) e executar o restante da query em memória.
var resultado = dbContext.Produtos
.Where(p => p.Ativo)
.AsEnumerable()
.Where(p => MinhaFuncaoLocal(p));
AsQueryable
Converte IEnumerable<T> para IQueryable<T>, permitindo composição de queries com Expression Trees.
IQueryable<string> query = nomes.AsQueryable().Where(n => n.Length > 3);
Cast
Faz cast de todos os elementos para o tipo especificado. Lança exceção se algum elemento não for compatível.
var objetos = new ArrayList { "Ana", "Bruno", "Carol" };
IEnumerable<string> strings = objetos.Cast<string>();
OfType
Filtra e faz cast apenas dos elementos do tipo especificado, ignorando os demais.
var misturado = new ArrayList { "Ana", 42, "Bruno", 3.14, "Carol" };
IEnumerable<string> somenteStrings = misturado.OfType<string>();
| Entrada | Saída |
|---|---|
| "Ana", 42, "Bruno", 3.14, "Carol" | "Ana", "Bruno", "Carol" |
7. Set (Conjuntos)
Operações entre coleções inspiradas na teoria dos conjuntos.
var a = new List<int> { 1, 2, 3, 4, 5 };
var b = new List<int> { 3, 4, 5, 6, 7 };
Concat
Concatena duas sequências (mantém duplicatas).
var resultado = a.Concat(b);
| A | B | Saída |
|---|---|---|
| 1,2,3,4,5 | 3,4,5,6,7 | 1,2,3,4,5,3,4,5,6,7 |
Union
Une duas sequências eliminando duplicatas.
var resultado = a.Union(b);
| A | B | Saída |
|---|---|---|
| 1,2,3,4,5 | 3,4,5,6,7 | 1,2,3,4,5,6,7 |
Except
Retorna elementos de A que não estão em B (diferença).
var resultado = a.Except(b);
| A | B | Saída |
|---|---|---|
| 1,2,3,4,5 | 3,4,5,6,7 | 1,2 |
Intersect
Retorna apenas os elementos presentes em ambas as coleções.
var resultado = a.Intersect(b);
| A | B | Saída |
|---|---|---|
| 1,2,3,4,5 | 3,4,5,6,7 | 3,4,5 |
8. Element (Elementos Individuais)
Métodos para obter um único elemento da coleção.
var numeros = new List<int> { 10, 20, 30, 40, 50 };
First / FirstOrDefault
Retorna o primeiro elemento (ou o primeiro que satisfaz um predicado). First lança exceção se vazio; FirstOrDefault retorna o valor padrão do tipo.
var primeiro = numeros.First(); // 10
var primeiroPar = numeros.First(n => n > 25); // 30
var nenhum = numeros.FirstOrDefault(n => n > 100); // 0
Last / LastOrDefault
Retorna o último elemento (ou o último que satisfaz um predicado).
var ultimo = numeros.Last(); // 50
var ultimoAbaixo40 = numeros.Last(n => n < 40); // 30
Single / SingleOrDefault
Retorna exatamente um elemento. Lança exceção se houver zero ou mais de um resultado. Útil quando você quer garantir unicidade.
var unico = numeros.Single(n => n == 30); // 30
var nulo = numeros.SingleOrDefault(n => n == 99); // 0
ElementAt / ElementAtOrDefault
Retorna o elemento em um índice específico.
var terceiro = numeros.ElementAt(2); // 30
var foraDoRange = numeros.ElementAtOrDefault(10); // 0
| Índice | Entrada | Saída |
|---|---|---|
| 2 | 10, 20, 30, 40, 50 | 30 |
| 10 | 10, 20, 30, 40, 50 | 0 (padrão) |
9. Aggregation (Agregação)
Métodos que reduzem uma coleção a um único valor.
var salarios = new List<double> { 3500, 5200, 4800, 6100, 2900 };
Count
Conta o número de elementos (opcionalmente com filtro).
var total = salarios.Count(); // 5
var acimaDe4000 = salarios.Count(s => s > 4000); // 3
Sum
Soma todos os valores.
var totalSalarios = salarios.Sum(); // 22500
Average
Calcula a média.
var media = salarios.Average(); // 4500
Min / Max
Retorna o menor ou maior valor.
var menor = salarios.Min(); // 2900
var maior = salarios.Max(); // 6100
| Método | Entrada | Saída |
|---|---|---|
| Count() | 3500,5200,4800,6100,2900 | 5 |
| Sum() | 3500,5200,4800,6100,2900 | 22500 |
| Average() | 3500,5200,4800,6100,2900 | 4500 |
| Min() | 3500,5200,4800,6100,2900 | 2900 |
| Max() | 3500,5200,4800,6100,2900 | 6100 |
Aggregate
Aplica uma função acumuladora elemento a elemento — o método mais flexível de todos.
var numeros = new List<int> { 1, 2, 3, 4, 5 };
// Calcula o fatorial: 1 * 2 * 3 * 4 * 5
var fatorial = numeros.Aggregate((acumulador, atual) => acumulador * atual);
// Resultado: 120
// Com valor semente e transformação final
var resultado = numeros.Aggregate(
seed: 100,
func: (acc, n) => acc + n,
resultSelector: total => $"Soma com semente: {total}"
);
// Resultado: "Soma com semente: 115"
| Entrada | Operação | Saída |
|---|---|---|
| 1,2,3,4,5 | acc * atual | 120 |
10. Quantifiers (Quantificadores)
Métodos que retornam bool sobre uma condição na coleção.
var notas = new List<int> { 7, 8, 5, 9, 6 };
Any
Retorna true se algum elemento satisfaz a condição (ou se a coleção não está vazia).
var temReprovado = notas.Any(n => n < 6); // false
var temElementos = notas.Any(); // true
All
Retorna true se todos os elementos satisfazem a condição.
var todosAprovados = notas.All(n => n >= 5); // true
var todosAcimaDe8 = notas.All(n => n > 8); // false
Contains
Retorna true se a coleção contém o elemento especificado.
var temNota9 = notas.Contains(9); // true
var temNota10 = notas.Contains(10); // false
SequenceEqual
Retorna true se duas sequências possuem os mesmos elementos na mesma ordem.
var lista1 = new List<int> { 1, 2, 3 };
var lista2 = new List<int> { 1, 2, 3 };
var lista3 = new List<int> { 3, 2, 1 };
lista1.SequenceEqual(lista2); // true
lista1.SequenceEqual(lista3); // false
| Sequência A | Sequência B | Saída |
|---|---|---|
| 1, 2, 3 | 1, 2, 3 | true |
| 1, 2, 3 | 3, 2, 1 | false |
11. Generation (Geração)
Métodos estáticos que criam sequências sem precisar de uma coleção de entrada.
Range
Gera uma sequência de inteiros consecutivos.
var de1a10 = Enumerable.Range(1, 10);
// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
| Start | Count | Saída |
|---|---|---|
| 1 | 10 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 |
| 5 | 5 | 5, 6, 7, 8, 9 |
Repeat
Gera uma sequência com o mesmo valor repetido N vezes.
var zeros = Enumerable.Repeat(0, 5);
// 0, 0, 0, 0, 0
var defaults = Enumerable.Repeat("N/A", 3);
// "N/A", "N/A", "N/A"
| Element | Count | Saída |
|---|---|---|
| 0 | 5 | 0, 0, 0, 0, 0 |
| "N/A" | 3 | "N/A", "N/A", "N/A" |
Empty
Retorna uma sequência vazia do tipo especificado. Útil para evitar null e como valor neutro em composições.
IEnumerable<string> vazia = Enumerable.Empty<string>();
// Útil em combinações:
var resultado = fonte ?? Enumerable.Empty<string>();
Conclusão
O LINQ é uma das features que mais diferencia o C# de outras linguagens. Dominar seus métodos significa escrever código mais expressivo, conciso e seguro — e evitar aquelas classes de util com loops manuais que todo projeto acumula com o tempo.
Um bom ponto de partida é se familiarizar primeiro com Where, Select, OrderBy, GroupBy e as agregações básicas. Os métodos de Join, SelectMany, Aggregate e Generation vêm naturalmente com a prática.
Dica: O LINQ usa execução adiada (deferred execution) — a query só é executada quando você itera sobre o resultado (com
foreach,ToList(),ToArray(), etc.). Isso é importante para performance e para evitar comportamentos inesperados.