Collection was modified: cómo vencer el error de iteración de colecciones

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: Conozca el error que ha roto código millones de veces



¿Alguna vez ha escrito un simple foreach, ejecutó el programa y, de repente, ¡pum! aparece un InvalidOperationException con un mensaje aterrador: "Collection was modified; enumeration operation may not execute"? Si es así, no está solo. Esta pregunta en Stack Overflow ha acumulado miles de visitas, y la hacen tanto principiantes como desarrolladores experimentados.



En este artículo, analizaremos por qué ocurre este error, cómo reproducirlo y, lo más importante, cómo evitarlo. Veremos tres métodos probados, escribiremos código real en C# y le daremos un plan de acción claro. ¡Allá vamos!



¿Qué es "Collection was modified"? Análisis del error



El error Collection was modified; enumeration operation may not execute es una excepción de tipo InvalidOperationException que se lanza cuando intenta modificar una colección (agregar, eliminar o reemplazar un elemento) mientras la itera con foreach u otro enumerador (IEnumerator).



Imagine que está leyendo un libro y alguien arranca páginas al mismo tiempo. Se pierde, no sabe qué leer a continuación. Así mismo, el enumerador no sabe cómo continuar si la colección cambia sobre la marcha.



¿Cómo se ve el código que causa el error?

Aquí hay un ejemplo clásico que garantiza provocar el error:



List<string> fruits = new List<string> { "apple", "banana", "cherry", "date" };

foreach (var fruit in fruits){ if (fruit == "banana") { fruits.Remove(fruit); // ¡Error! Collection was modified }}


Ejecute este código y obtendrá InvalidOperationException en la segunda iteración. ¿Por qué? Porque foreach usa un enumerador interno que bloquea los cambios en la colección durante el recorrido.



¿Por qué ocurre esto? Miremos bajo el capó de C#



Cuando escribe foreach, el compilador de C# lo convierte en una llamada al método GetEnumerator(). Este método devuelve un objeto IEnumerator que almacena el estado del recorrido (índice actual, versión de la colección). Cada vez que la colección se modifica (a través de Add, Remove, Clear, etc.), su contador de versión interno aumenta. El enumerador verifica esta versión en cada paso. Si no coincide, se lanza la excepción.



Esto se hizo para protegerse de comportamientos indefinidos. Imagine que elimina un elemento del medio de la lista: los índices de todos los elementos siguientes se desplazan y el enumerador podría saltarse un elemento o procesar el mismo dos veces. Los desarrolladores de .NET decidieron que es mejor lanzar una excepción que permitir un error lógico inadvertido.



Top 3 formas de evitar el error "Collection was modified"



Ahora que conocemos al enemigo, analicemos cómo vencerlo. Hay tres enfoques principales, y cada uno es adecuado para diferentes situaciones.



Forma 1: Copiar la colección antes de iterar

El método más simple y seguro es crear una copia de la colección e iterar sobre ella, mientras se realizan cambios en el original.



List<string> fruits = new List<string> { "apple", "banana", "cherry", "date" };

// Creamos una copia de la lista para iterarforeach (var fruit in fruits.ToList()) // o new List<string>(fruits){ if (fruit == "banana") { fruits.Remove(fruit); // Ahora es seguro }}

Console.WriteLine(string.Join(", ", fruits)); // Salida: apple, cherry, date


Ventajas: Simplicidad, legibilidad, adecuado para colecciones pequeñas.
Desventajas: Requiere memoria adicional, puede ser lento para listas grandes.



Consejo: Me

Blogs

Book Recommendations