web-dev-qa-db-fra.com

Comment parcourir les éléments d'une zone de liste, puis supprimer ces éléments?

J'obtiens l'erreur ci-dessous lorsque j'essaie de parcourir une zone de liste, puis de supprimer l'élément.

Liste à laquelle cet énumérateur est lié a été modifiée. Un énumérateur ne peut être utilisé que si la liste ne change pas.

foreach (string s in listBox1.Items)
{
    MessageBox.Show(s);
    //do stuff with (s);
    listBox1.Items.Remove(s);
}

Comment puis-je supprimer l'élément et continuer à parcourir le contenu?

19
Ben H

Voulez-vous supprimer tous les éléments? Si c'est le cas, faites d'abord le foreach, puis utilisez simplement Items.Clear() pour les supprimer tous par la suite.

Sinon, bouclez peut-être en arrière par l'indexeur:

listBox1.BeginUpdate();
try {
  for(int i = listBox1.Items.Count - 1; i >= 0 ; i--) {
    // do with listBox1.Items[i]

    listBox1.Items.RemoveAt(i);
  }
} finally {
  listBox1.EndUpdate();
}
37
Marc Gravell

Tout le monde a posté une réponse "revenir en arrière", je vais donc donner l'alternative: créez une liste des éléments que vous souhaitez supprimer, puis supprimez-les à la fin:

List<string> removals = new List<string>();
foreach (string s in listBox1.Items)
{
    MessageBox.Show(s);
    //do stuff with (s);
    removals.Add(s);
}

foreach (string s in removals)
{
    listBox1.Items.Remove(s);
}

Parfois, la méthode "travailler en arrière" est meilleure, parfois ce qui précède est meilleur - en particulier si vous avez affaire à un type qui a une méthode RemoveAll(collection). Cela vaut la peine de savoir les deux cependant.

25
Jon Skeet

Voici ma solution sans revenir en arrière et sans liste temporaire

while (listBox1.Items.Count > 0)
{
  string s = listBox1.Items[0] as string;
  // do something with s
  listBox1.Items.RemoveAt(0);
}
11
nruessmann

Vous devez parcourir la collection du dernier article au premier. ce code est en vb

for i as integer= list.items.count-1 to 0 step -1
....
list.items.removeat(i)
next
1
Jefferson

Jefferson a raison, vous devez le faire à l'envers.

Voici l'équivalent c #:

for (var i == list.Items.Count - 1; i >= 0; i--)
{
    list.Items.RemoveAt(i);
}
1
Jon Limjap

while(listbox.Items.Remove(s)) ; devrait également fonctionner. Cependant, je pense que la solution à l'envers est le le plus rapide.

1
ThunderGr

Que diriez-vous:

foreach(var s in listBox1.Items.ToArray())
{
    MessageBox.Show(s);
    //do stuff with (s);
    listBox1.Items.Remove(s);
}

Le ToArray crée une copie de la liste, vous n'avez donc pas à vous soucier de la modification de la liste pendant que vous la traitez.

1
Matthew Wright

Vous ne pouvez pas modifier la collection en cours d'itération dans le bloc ForEach.

Une solution rapide consiste à parcourir une copie de la collection. Un moyen simple de faire cette copie est d'utiliser le constructeur ArrayList. Les objets DataRowView de la collection copiée feront référence et pourront modifier les mêmes données sous-jacentes que votre code.

For Each item As DataRowView In New System.Collections.ArrayList(lbOrdersNeedToBeVoided.Items)

veuillez lire http://social.msdn.Microsoft.com/Forums/en-AU/vbgeneral/thread/b4d1f649-d78a-4e5b-8ad8-1940e3379bed

0
Somnath Kadam