Выпуск "Коллекция была изменена ..." - PullRequest
2 голосов
/ 25 мая 2010

У меня есть функция, которая проверяет список объектов, чтобы увидеть, были ли они нажаты, и соответственно запускает события OnClick. Я считаю, что функция работает правильно, но у меня проблема:

Когда я подключаюсь к одному из событий OnClick, удаляю и вставляю элемент в другое место в списке (типичная функциональность для этой программы), я получаю ошибку «Коллекция была изменена ...».

Мне кажется, я понимаю, что происходит:

  • Функция циклически перебирает каждый объект, вызывая события OnClick, где это необходимо.
  • Событие запускается, и объект меняет места в списке в соответствии с подключенной функцией
  • Исключение выдается для изменения коллекции при ее итерации по ней

У меня вопрос: как мне разрешить функции выполнять итерацию по всем объектам, запускать необходимые события в нужное время и при этом давать пользователю возможность манипулировать положением объекта в списке?

Ответы [ 5 ]

7 голосов
/ 25 мая 2010

Существует два основных решения этой проблемы:

  • Сделайте копию списка. Перебрать копию.
  • Составьте список изменений, которые должны произойти. Примените изменения после завершения итерации.

Опция «использовать индексы» не звучит так, как будто она подходит, если вы хотите отделить код, который вносит изменения, от кода, который выполняет зацикливание.

2 голосов
/ 25 мая 2010

Поведение, которое вы видите, по замыслу :

оператор foreach для C # язык (для каждого в Visual Basic) скрывает сложность счетчики. Поэтому, используя foreach рекомендуется вместо прямого манипулирование счетчиком.

Счетчики могут использоваться для чтения данные в сборе, но они не может быть использован для изменения базовая коллекция.

Запуск события, которое выполняется синхронно, имеет тот же эффект, что и изменение коллекции из цикла foreach.

Я предпочитаю использовать цикл for в обратном направлении, это позволяет избежать условной логики обновления индекса цикла в зависимости от того, вставляете ли вы что-то:

for (var i = collection.Count - 1; i >= 0; i--) {
  if (condition)
    collection.Insert(i, item);
}

Соответствующий инкрементный цикл будет выглядеть примерно так:

for (var i = 0; i < collection.Count; i++) {
  if (condition) {
    collection.Insert(i, item);
    i++;
  }
}
2 голосов
/ 25 мая 2010

Если вы используете цикл foreach для управления коллекцией, попробуйте заменить ее на

for (int a = items_count - 1; a >= 0; --a)
2 голосов
/ 25 мая 2010
  • Использовать копию коллекции вместо начальной коллекции для итерации.

  • Если у вас есть коллекция, которая поддерживает индексы (например, List), вы можете использовать цикл for вместо итерации с foreach.

1 голос
/ 25 мая 2010

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

List itemsTobeRemoved = новый список (); for (var i = 0; i

foreach (var i = 0 в itemsTobeRemoved) { if (условие) { collection.RemoveAt (я); }

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...