Introduction : Découvrez l'erreur qui a cassé du code des millions de fois
Avez-vous déjà écrit un simple foreach, lancé le programme, et soudain — bam ! — une InvalidOperationException apparaît avec un message effrayant : "Collection was modified; enumeration operation may not execute" ? Si oui, vous n'êtes pas seul. Cette question sur Stack Overflow a recueilli des milliers de vues, et elle est posée autant par les débutants que par les développeurs expérimentés.
Dans cet article, nous allons analyser pourquoi cette erreur se produit, comment la reproduire, et surtout comment l'éviter. Nous examinerons trois méthodes éprouvées, écrirons du code réel en C# et vous donnerons un plan d'action clair. C'est parti !
Qu'est-ce que "Collection was modified" ? Analyse de l'erreur
L'erreur Collection was modified; enumeration operation may not execute est une exception de type InvalidOperationException qui est levée lorsque vous essayez de modifier une collection (ajouter, supprimer ou remplacer un élément) pendant son itération avec foreach ou un autre énumérateur (IEnumerator).
Imaginez que vous lisez un livre, et que quelqu'un en arrache des pages en même temps. Vous êtes perdu, vous ne savez plus quoi lire ensuite. C'est la même chose pour l'énumérateur : il ne sait pas comment continuer si la collection change en cours de route.
À quoi ressemble le code qui provoque l'erreur ?
Voici un exemple classique qui mènera assurément à l'erreur :
List<string> fruits = new List<string> { "apple", "banana", "cherry", "date" };
foreach (var fruit in fruits){ if (fruit == "banana") { fruits.Remove(fruit); // Erreur ! Collection was modified }}Exécutez ce code — et vous obtiendrez une InvalidOperationException à la deuxième itération. Pourquoi ? Parce que foreach utilise un énumérateur interne qui bloque les modifications de la collection pendant le parcours.
Pourquoi cela se produit-il ? Regardons sous le capot de C#
Lorsque vous écrivez foreach, le compilateur C# le transforme en un appel à la méthode GetEnumerator(). Cette méthode retourne un objet IEnumerator qui stocke l'état du parcours (l'index courant, la version de la collection). Chaque fois que la collection est modifiée (via Add, Remove, Clear, etc.), son compteur de version interne est incrémenté. L'énumérateur vérifie cette version à chaque étape. Si elle ne correspond pas, l'exception est levée.
Cela a été fait pour se protéger contre un comportement indéfini. Imaginez que vous supprimez un élément du milieu d'une liste : les index de tous les éléments suivants sont décalés, et l'énumérateur pourrait sauter un élément ou en traiter deux fois le même. Les développeurs de .NET ont décidé qu'il valait mieux lever une exception que de permettre une erreur logique imperceptible.
Top 3 des méthodes pour éviter l'erreur "Collection was modified"
Maintenant que nous connaissons l'ennemi, voyons comment le vaincre. Il existe trois approches principales, chacune adaptée à différentes situations.
Méthode 1 : Copier la collection avant l'itération
La méthode la plus simple et la plus sûre est de créer une copie de la collection et de l'itérer, tout en appliquant les modifications à l'original.
List<string> fruits = new List<string> { "apple", "banana", "cherry", "date" };
// Créer une copie de la liste pour l'itérationforeach (var fruit in fruits.ToList()) // ou new List<string>(fruits){ if (fruit == "banana") { fruits.Remove(fruit); // Maintenant c'est sûr }}
Console.WriteLine(string.Join(", ", fruits)); // Sortie : apple, cherry, dateAvantages : Simplicité, lisibilité, adapté aux petites collections.
Inconvénients : Nécessite de la mémoire supplémentaire, peut être lent pour les grandes listes.
Conseil : Me