Коллекция была изменена; операция перечисления не может выполняться в ArrayList [дубликат]



этот вопрос уже есть ответ здесь:



Я пытаюсь удалить элемент из ArrayList и я получаю это исключение:
Collection was modified; enumeration operation may not execute.



какие идеи?

686   9  

9 ответов:

вы удаляете элемент во время foreach, да? Просто, вы не можете. Существует несколько распространенных вариантов здесь:

  • использовать List<T> и RemoveAll С
  • выполнить итерации в обратном направлении по индексу, удаление соответствующие элементы

    for(int i = list.Count - 1; i >= 0; i--) {
        if({some test}) list.RemoveAt(i);
    }
    
  • использовать foreach, и поместите соответствующие элементы во второй список; теперь перечислите второй список и удалите эти элементы из первого (если вы видите, что я имею в виду)

вот пример (извините за возможные описки)

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);
}

или если вы используете 3.5, Linq делает Первый БИТ проще:

itemsToRemove = originalArrayList
  .Where(item => ...)
  .ToArray();

foreach (var item in itemsToRemove) {
  originalArrayList.Remove(item);
}

заменить "..."с вашим условием, которое определяет, должен ли элемент быть удален.

один из способов-добавить удаляемые элементы в новый список. Затем перейдите и удалите эти элементы.

мне нравится повторять назад с помощью for петли, но это может стать утомительным по сравнению с foreach. Одно из решений, которое мне нравится, - это создать перечислитель, который пересекает список назад. Вы можете реализовать это как метод расширения на ArrayList или List<T>. Реализация для ArrayList ниже.

    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];
        }
    }

реализация List<T> аналогично.

    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];
        }
    }

в приведенном ниже примере перечислитель используется для удаления всех четных целых чисел из ArrayList.

    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);
    }

не изменяйте список внутри цикла, который повторяется через список.

используйте for() или while() с индексом, идя назад по списку. (Это позволит вам удалить вещи без получения недопустимого индекса.)
var foo = new List<Bar>();

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

Я что-то пропустила? Кто-нибудь поправьте меня, если я ошибаюсь.

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

вместо foreach() используйте цикл for () с числовым индексом.

Я согласен с несколькими пунктами, которые я прочитал в этом посте, и я включил их в свое решение, чтобы решить ту же проблему, что и исходная публикация.

тем не менее, комментарии, которые я оценил:

  • " Если вы не используете .NET 1.0 или 1.1, используйте List<T> вместо ArrayList. "

  • " кроме того, добавить пункт(ы) для удаления в новый список. Затем перейдите и удалите эти элементы." .. в моем случае я просто создал новую Список и заполненный им с допустимыми значениями данных.

например

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;
}        

используя ArrayList также вы можете попробовать такой

ArrayList arraylist = ... // myobject data list

ArrayList temp = (ArrayList)arraylist.Clone();

foreach (var item in temp)
{
      if (...)
         arraylist.Remove(item);
}

Comments

    Ничего не найдено.