Я пытаюсь удалить элемент из ArrayList
, и я получаю это исключение: Collection was modified; enumeration operation may not execute.
Любые идеи?
Я пытаюсь удалить элемент из ArrayList
, и я получаю это исключение: Collection was modified; enumeration operation may not execute.
Любые идеи?
Вы удаляете элемент во время 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 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);
}