Enumerator, foreach e o erro “InvalidOperationException: Collection Was Modified”

C#

Vamos abordar o cenário mais comum: Você possui uma coleção que pode ser uma lista de string, int ou como neste caso uma coleção de uma classe qualquer. Sua coleção tem diversos itens adicionados e você necessita retirar os itens conforme uma determinada lógica de negócio. Observe o código abaixo:

«««< HEAD

Listagem 1

 

=======

Listagem 1

>>>>>>> fc19c35aaf9d0aae2c5a94f9ddc93deb1b95af77

O motivo

Você utiliza um loop foreach para percorrer cada item da coleção. Assim que sua regra é atendida por um dos itens da coleção, chamamos o método Remove() que tenta modificar a coleção durante o laço foreach.

O erro

A mensagem retornada no InvalidOperationException é bem clara: A coleção foi modifica e a enumeração não pode ser executada.

O primeiro passo para entender o erro é saber como funciona a forma básica de um foreach. O loop foreach foi criado para proporcionar uma forma elegante e simples de varrer todos os elementos de uma determinada coleção. Um foreach não utiliza índices inteiros em suas iterações, em vez disso, ele usa um mecanismo que retorna cada elemento em ordem. Este mecanismo é chamado de enumerator. Ele foi criado para evitar os erros comuns causados pelo manuseio incorreto de índices.

Um enumerator é um cursor somente leitura (read-only), sequencial (forward-only) em uma sequencia de valores. Ele implementa IEnumerator ou IEnumerator<T>.

O foreach consulta o enumerator da coleção e solicita o próximo elemento lista. Em nosso exemplo, quando removemos um item tornamos o enumerator inválido já que o mesmo aponta para o estado atual do loop. O enumerator guarda uma cópia do layout da coleção. Não é possível para o foreach em tempo de execução (runtime) saber que o item foi removido. Logo, quando alteramos a coleção dentro de um loop foreach, o enumerator se perde…

Sendo assim, toda vez que retiramos um item durante a iteração com a lista, ocorrerá o erro assim que o laço “pegar” o próximo item.

A solução

Existem várias estratégias para isto, a maioria envolve trabalhar com listas auxiliares e é exatamente isto que quero evitar.

Levando em consideração aquilo que já sabemos sobre o funcionamento do foreach, podemos solucionar o problema de satisfatória apenas substituindo a linha do foreach pela sintaxe abaixo:

<<<<<<< HEAD

Listagem 2

O que ocorre é que para cada iteração trabalhamos com uma nova cópia da lista, o que evita o erro de coleção modificada…

O código fonte do exemplo pode ser baixado aqui!

 

=======

Listagem 2

O que ocorre é que para cada iteração trabalhamos com uma nova cópia da lista, o que evita o erro de coleção modificada…

O código fonte do exemplo pode ser baixado aqui!

>>>>>>> fc19c35aaf9d0aae2c5a94f9ddc93deb1b95af77

Um ótimo feriado a todos.


Author's profile picture

Vitor is a computer scientist who is passionate about creating software that will positively change the world we live in.

MVP Azure - Cloud Architect - Data science enthusiast


2 minutes to read