2010-06-09 4 views
6

Possible Duplicates:
Exception during iteration on collection and remove items from that collection
How to remove elements from a generic list while iterating around it?
Better way to remove matched items from a listcomment correctement Supprimer l'élément de la liste

// tmpClientList is List<Client> type 

if (txtboxClientName.Text != "") 
    foreach (Client cli in tmpClientList) 
     if (cli.Name != txtboxClientName.Text) 
      tmpClientList.Remove(cli); 

Erreur: « Collection a été modifiée, l'opération d'énumération ne peut pas exécuter. » Comment puis-je supprimer des éléments de la liste, d'une manière simple, sans enregistrer les index de ces éléments dans une autre liste ou un tableau, et les supprimer à un autre endroit dans le code. J'ai essayé aussi RemoveAt (index) mais c'est exactement la même situation, en modifiant quand la boucle s'exécute.

+0

D'accord sur les problèmes de doublons exacts, voir le lien http://stackoverflow.com/questions/1154325/better-way-to-remove-matched-items-from-a-list et de lier deux: http: //stackoverflow.com/questions/1541777/can-you-remove-an-item-from-a-list-whilst-itering-through-it-in-c – CrimsonX

Répondre

1

Le problème est que vous essayez de modifier la liste dans une itération foreach. Remplacer cela par un pour et vous devriez être ok.

En outre, puisque vous semblez utiliser l'entrée utilisateur pour le nom, pensez à nettoyer l'entrée un bit, au moins avec un Trim() pour supprimer les espaces blancs supplémentaires. Si vous ne le faites pas, 'John' et 'John' seront deux choses différentes. Identique à la vérification initiale! = "".

+0

vous voulez dire que "" et "" serait le même, et je dois couper l'entrée dans cette situation aussi (lorsque l'utilisateur tape uniquement des caractères blancs en entrée)? – qlf00n

+0

@dygi: oui. supprimer les espaces blancs ne laisse que les informations pertinentes - ce qui dans ce cas est aucun. Comme pour un cas où cela pourrait arriver: L'utilisateur commence à taper le nom, y compris un espace après, puis décide de supprimer les caractères et l'espace reste, car il ne peut pas le 'voir'. – Rox

2

Ne pas utiliser foreach. Utilisez et descendez la liste (c'est-à-dire commencez à partir de la fin), en utilisant RemoveAt.

Ainsi,

// tmpClientList is List<Client> type 

if (txtboxClientName.Text != "") 
    foreach (int pos = tmpClientList.Length - 1; pos >= 0; pos--) 
    { 
     Client cli = tmpClientList[pos]; 
     if (cli.Name != txtboxClientName.Text) 
      tmpClientList.RemoveAt(pos); 
    } 
4

Soit utiliser un pour/en boucle, ou tmpClientList.RemoveAll(a => a.Name == txtboxClientName.Text). Comme vous n'avez pas spécifié quelle version de C# vous utilisez, ymmw.

+1

Et quand confiné à 2.0, c'est juste un peu plus verbeux: 'tmpClientList.RemoveAll (délégué (client a) {return a.Name == txtboxClientName.Text;});' – Humberto

11

Reculer dans la liste. Ainsi, la suppression d'un élément n'affecte pas l'élément suivant.

for(var i=tmpClientList.Count-1;i>=0;i--) 
{ 
    if (tmpClientList[i].Name != txtboxClientName.Text) 
      tmpClientList.RemoveAt(i); 

} 
+0

belle solution simple, merci pour le partage – qlf00n

11

Sur un List<T>, il existe une méthode RemoveAll qui prend un délégué pour indiquer si vous souhaitez supprimer l'élément. Vous pouvez l'utiliser comme ceci:

tmpCLientList.RemoveAll(cli => cli.Name != txtboxClientName.Text); 
+0

+1 Il faut noter que cela ne fonctionne que pour C# 3.0 et plus. L'OP a étiqueté la question avec les versions 2, 3 et 4 :-) –

+1

@Jakob: Si l'OP n'utilise pas C# 3 ou plus récent, ils peuvent appeler 'RemoveAll' avec la syntaxe old-skool delegate:' tmpCLientList.RemoveAll (délégué cli) {return cli.Name! = txtboxClientName.Text;}); ' – LukeH

+0

Oh, à droite - pensé que RemoveAll était une méthode d'extension. Désolé à ce sujet :-) –

1

Vous pouvez créer une autre liste avec les éléments que vous souhaitez supprimer et itérer la nouvelle liste pour supprimer les éléments de votre liste « txtboxClientName ».

+0

À droite, je peux utiliser les méthodes Contains() et Remove() sur la liste de copie, tout en itérant sur l'original. Merci. – qlf00n

1

En fait, foreach utilise des énumérateurs pour effectuer des itérations à travers des collections d'articles données. En allant plus loin, le System.Collections.Generic.List<T> implémente le IEnumarable-Interface à provide a Class, qui sait parcourir les éléments de la liste, c'est-à-dire Enumerator. Maintenant, si vous parcourez cette liste en utilisant foreach, l'énumérateur garde la trace de la position actuelle, comment atteindre la position suivante et d'autres choses. La logique interne peut être quelque chose comme le stockage du nombre d'éléments dans une variable n et ensuite accéder à tous les objets de 0 à n-1. Comme vous pouvez le constater si un objet est supprimé entre les étapes d'itération, nous terminerons par un NullReferenceException lorsque l'énumérateur essaiera de fournir le dernier objet de la liste. Ainsi, pour éviter les échecs d'itération, la liste elle-même n'est pas autorisée à être modifiée pendant l'énumération. J'espère que j'ai été capable de le dire au moins un peu globalement. :-)

+0

merci pour des informations très précises, GTK comment ça fonctionne en interne – qlf00n

Questions connexes