Introdução: Conheça o erro que quebrou códigos milhões de vezes
Você já escreveu um simples foreach, executou o programa e, de repente — bum! — aparece um InvalidOperationException com a mensagem assustadora: "Collection was modified; enumeration operation may not execute"? Se sim, você não está sozinho. Esta pergunta no Stack Overflow acumulou milhares de visualizações, e é feita tanto por iniciantes quanto por desenvolvedores experientes.
Neste artigo, vamos analisar por que esse erro ocorre, como reproduzi-lo e, o mais importante, como evitá-lo. Veremos três formas comprovadas, escreveremos código real em C# e daremos a você um plano de ação claro. Vamos lá!
O que é "Collection was modified"? Análise do erro
O erro Collection was modified; enumeration operation may not execute é uma exceção do tipo InvalidOperationException que é lançada quando você tenta modificar uma coleção (adicionar, remover ou substituir um elemento) durante sua iteração com foreach ou outro enumerador (IEnumerator).
Imagine que você está lendo um livro e alguém arranca páginas dele ao mesmo tempo. Você se perde, não sabe o que ler em seguida. Assim também funciona o enumerador: ele não sabe como continuar se a coleção muda durante a execução.
Como é o código que causa o erro?
Aqui está um exemplo clássico que certamente levará ao erro:
List<string> fruits = new List<string> { "apple", "banana", "cherry", "date" };
foreach (var fruit in fruits){ if (fruit == "banana") { fruits.Remove(fruit); // Erro! Collection was modified }}Execute este código — e você obterá InvalidOperationException na segunda iteração. Por quê? Porque o foreach usa um enumerador interno que bloqueia alterações na coleção durante a iteração.
Por que isso acontece? Uma olhada nos bastidores do C#
Quando você escreve foreach, o compilador C# o converte em uma chamada ao método GetEnumerator(). Este método retorna um objeto IEnumerator que armazena o estado da iteração (índice atual, versão da coleção). Cada vez que a coleção é modificada (via Add, Remove, Clear, etc.), seu contador interno de versão é incrementado. O enumerador verifica essa versão a cada passo. Se não coincidir — a exceção é lançada.
Isso foi feito para proteção contra comportamento indefinido. Imagine que você remove um elemento do meio da lista: os índices de todos os elementos subsequentes são deslocados, e o enumerador pode pular um elemento ou processar o mesmo duas vezes. Os desenvolvedores do .NET decidiram que é melhor lançar uma exceção do que permitir um erro lógico imperceptível.
Top 3 formas de evitar o erro "Collection was modified"
Agora que conhecemos o inimigo de vista, vamos analisar como vencê-lo. Existem três abordagens principais, e cada uma é adequada para diferentes situações.
Forma 1: Copiar a coleção antes da iteração
O método mais simples e seguro — criar uma cópia da coleção e iterar sobre ela, enquanto as modificações são feitas no original.
List<string> fruits = new List<string> { "apple", "banana", "cherry", "date" };
// Criamos uma cópia da lista para iteraçãoforeach (var fruit in fruits.ToList()) // ou new List<string>(fruits){ if (fruit == "banana") { fruits.Remove(fruit); // Agora é seguro }}
Console.WriteLine(string.Join(", ", fruits)); // Saída: apple, cherry, dateVantagens: Simplicidade, legibilidade, adequado para coleções pequenas.
Desvantagens: Requer memória adicional, pode ser lento para listas grandes.
Dica: Me