Verzameling is gewijzigd; opsommingsbewerking wordt mogelijk niet uitgevoerd in ArrayList

Ik probeer een item te verwijderen uit een ArrayListen ik krijg deze uitzondering:
Collection was modified; enumeration operation may not execute.

Enig idee?


Antwoord 1, autoriteit 100%

Je verwijdert het item tijdens een foreach, ja? Gewoon, dat kan niet. Er zijn een paar veelvoorkomende opties:

  • gebruik List<T>en RemoveAllmet een predikaat
  • terug op index herhalen, overeenkomende items verwijderen

    for(int i = list.Count - 1; i >= 0; i--) {
        if({some test}) list.RemoveAt(i);
    }
    
  • gebruik foreachen plaats overeenkomende items in een tweede lijst; noem nu de tweede lijst op en verwijder die items uit de eerste (als je begrijpt wat ik bedoel)


Antwoord 2, autoriteit 12%

Hier is een voorbeeld (sorry voor eventuele typefouten)

var itemsToRemove = new ArrayList();  // should use generic List if you can
foreach (var item in originalArrayList) {
  if (...) {
    itemsToRemove.Add(item);
  }
}
foreach (var item in itemsToRemove) {
  originalArrayList.Remove(item);
}

OF als je 3.5 gebruikt, maakt Linq het eerste stukje makkelijker:

itemsToRemove = originalArrayList
  .Where(item => ...)
  .ToArray();
foreach (var item in itemsToRemove) {
  originalArrayList.Remove(item);
}

Vervang “…” door uw voorwaarde die bepaalt of het item moet worden verwijderd.


Antwoord 3, autoriteit 4%

Eén manier is om de te verwijderen item(s) toe te voegen aan een nieuwe lijst. Ga dan door en verwijder die items.


Antwoord 4, autoriteit 4%

Ik vind het leuk om achteruit te itereren met behulp van een for-lus, maar dit kan vervelend worden in vergelijking met foreach. Een oplossing die ik leuk vind, is om een ​​enumerator te maken die de lijst achteruit doorloopt. U kunt dit implementeren als een uitbreidingsmethode op ArrayListof List<T>. De implementatie voor ArrayListstaat hieronder.

   public static IEnumerable GetRemoveSafeEnumerator(this ArrayList list)
    {
        for (int i = list.Count - 1; i >= 0; i--)
        {
            // Reset the value of i if it is invalid.
            // This occurs when more than one item
            // is removed from the list during the enumeration.
            if (i >= list.Count)
            {
                if (list.Count == 0)
                    yield break;
                i = list.Count - 1;
            }
            yield return list[i];
        }
    }

De implementatie voor List<T>is vergelijkbaar.

   public static IEnumerable<T> GetRemoveSafeEnumerator<T>(this List<T> list)
    {
        for (int i = list.Count - 1; i >= 0; i--)
        {
            // Reset the value of i if it is invalid.
            // This occurs when more than one item
            // is removed from the list during the enumeration.
            if (i >= list.Count)
            {
                if (list.Count == 0)
                    yield break;
                i = list.Count - 1;
            }
            yield return list[i];
        }
    }

Het onderstaande voorbeeld gebruikt de enumerator om alle even gehele getallen uit een ArrayListte verwijderen.

   ArrayList list = new ArrayList() {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    foreach (int item in list.GetRemoveSafeEnumerator())
    {
        if (item % 2 == 0)
            list.Remove(item);
    }

Antwoord 5, autoriteit 3%

Wijzig de lijst niet binnen een lus die door de lijst loopt.

Gebruik in plaats daarvan een for()of while()met een index, teruggaand door de lijst. (Hierdoor kun je dingen verwijderen zonder een ongeldige index te krijgen.)

var foo = new List<Bar>();
for(int i = foo.Count-1; i >= 0; --i)
{
  var item = foo[i];
  // do something with item
}

Antwoord 6, autoriteit 3%

Mis ik iets? Corrigeer me als ik het fout heb.

list.RemoveAll(s => s.Name == "Fred");

Antwoord 7

Gebruik in plaats van foreach() een for()-lus met een numerieke index.


Antwoord 8

Ik ben het eens met een aantal van de punten die ik in dit bericht heb gelezen en ik heb ze opgenomen in mijn oplossing om exact hetzelfde probleem op te lossen als het oorspronkelijke bericht.

Dat gezegd hebbende, de opmerkingen die ik op prijs stelde zijn:

  • “Tenzij u .NET 1.0 of 1.1 gebruikt, gebruikt u List<T>in plaats van ArrayList. “

  • “Voeg ook de te verwijderen items toe aan een nieuwe lijst. Ga vervolgens door en verwijder die items.”
    .. in mijn geval heb ik zojuist een nieuwe lijst gemaakt en deze gevuld met de geldige gegevenswaarden.

bijv.

private List<string> managedLocationIDList = new List<string>();
string managedLocationIDs = ";1321;1235;;" // user input, should be semicolon seperated list of values
managedLocationIDList.AddRange(managedLocationIDs.Split(new char[] { ';' }));
List<string> checkLocationIDs = new List<string>();
// Remove any duplicate ID's and cleanup the string holding the list if ID's
Functions helper = new Functions();
checkLocationIDs = helper.ParseList(managedLocationIDList);
...
public List<string> ParseList(List<string> checkList)
{
    List<string> verifiedList = new List<string>();
    foreach (string listItem in checkList)
    if (!verifiedList.Contains(listItem.Trim()) && listItem != string.Empty)
        verifiedList.Add(listItem.Trim());
    verifiedList.Sort();
    return verifiedList;
}        

Antwoord 9

met behulp van ArrayListkun je het ook zo proberen

ArrayList arraylist = ... // myobject data list
ArrayList temp = (ArrayList)arraylist.Clone();
foreach (var item in temp)
{
      if (...)
         arraylist.Remove(item);
}

Other episodes