Execução adiada e armadilhas
ResumoA maioria dos operadores LINQ não executa na hora — só quando você itera (ou chama
ToList,Count, etc.). Entender isso evita reexecução acidental e surpresas com dados que mudam.
1. Objetivos de Aprendizagem#
- Entender execução adiada (deferred) vs imediata.
- Reconhecer reenumeração acidental.
- Saber quando materializar com
ToList/ToArray.
2. Pré-requisitos#
- Operadores essenciais (tópico 8.2).
3. Conceito#
- Execução adiada: operadores como
Where,Select,OrderBynão rodam quando você os escreve — eles montam uma consulta. A execução acontece quando você itera (foreach) ou chama um operador imediato. - Execução imediata:
ToList,ToArray,Count,Sum,First... forçam a avaliação na hora.
O porquê de importar: se você itera a mesma consulta duas vezes, ela roda duas vezes. Sobre um Dictionary em memória isso é só desperdício; sobre o EF Core, são duas idas ao banco.
4. Mão na Massa#
4.1. Setup#
dotnet new console -n Catalog.Deferred
cd Catalog.Deferred
4.2. Implementação Passo a Passo#
- Adiada: a consulta enxerga mudanças posteriores à fonte:
var numeros = new List<int> { 1, 2, 3 };
var pares = numeros.Where(n => n % 2 == 0); // ainda não executou
numeros.Add(4);
foreach (var n in pares) // executa AGORA
Console.WriteLine(n); // 2, 4 (viu o 4 adicionado depois!)
- Reenumeração acidental:
var caros = numeros.Where(n => { Console.WriteLine($"avaliando {n}"); return n > 1; });
var count = caros.Count(); // avalia uma vez
var lista = caros.ToList(); // avalia DE NOVO
- Materializar uma vez:
var resultado = numeros.Where(n => n > 1).ToList(); // executa 1x
Console.WriteLine(resultado.Count);
foreach (var n in resultado) { /* usa sem reexecutar */ }
4.3. Executando#
dotnet run
5. Exemplo Completo#
Se você precisa do resultado mais de uma vez (contar e iterar), chame ToList() uma vez e reutilize a lista — evitando reexecutar a consulta (ou reconsultar o banco, no EF Core).
6. Boas Práticas e Armadilhas#
| Faça | Evite |
|---|---|
Materializar com ToList() quando for usar o resultado várias vezes | Iterar a mesma IEnumerable repetidamente sem perceber |
| Manter a consulta adiada quando itera só uma vez | ToList() prematuro que carrega tudo à memória sem necessidade |
Atençãono EF Core, chamar
ToList()cedo demais traz dados desnecessários do banco; chamar tarde demais pode reconsultar. Equilíbrio é chave — materialize quando for de fato usar o resultado múltiplas vezes.
7. Segurança e Produção#
- Reenumeração sobre
IQueryable(EF Core) multiplica consultas ao banco e degrada latência sob carga. Meça e materialize conscientemente.
8. Exercícios#
- Fácil: demonstre que uma consulta adiada "vê" um item adicionado depois.
- Médio: conte e liste a mesma consulta e observe a dupla avaliação com um
Console.WriteLineno predicado. - Desafio: explique a diferença entre
IEnumerable<T>eIQueryable<T>quanto a onde o filtro é executado.
9. Resumo#
LINQ é majoritariamente adiado: executa ao iterar ou em operadores imediatos. Evite reenumeração acidental materializando com ToList() quando for reutilizar o resultado — crucial com EF Core.
10. Próximos Passos#
Encerramos LINQ. A seguir, delegates, lambdas e eventos — a mecânica por trás das expressões que você passou ao LINQ.
11. Referências#
- Microsoft Learn — Execução adiada e imediata
- Microsoft Learn — IQueryable<T>
- Microsoft Learn — Consultas no EF Core