2010-05-25 4 views
2

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

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

Я считаю, что я понимаю, что происходит:

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

Мой вопрос, как я могу позволить функции для перебора ll объекты, своевременно запустить необходимые события и предоставить пользователю возможность манипулировать позицией объекта в списке?

ответ

7

Есть два основных пути решения проблемы такого рода:

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

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

+0

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

+0

Обратите внимание, что вам нужно четко указать, что означает «позиция», когда вы делаете несколько изменений - «обмениваете 1 и 2» и «свопите 2 и 3» или «переместите C после A» и «удалите А». Обычно я нахожу, что проще сделать код, который делает правильную вещь, итерации по копии, хотя это может быть ужасно неэффективно. –

2
  • Используйте копию коллекции вместо первоначальной коллекции для итерации.

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

+0

Или, список <>. ForEach() – Alan

+0

foreach по-прежнему вызывает ту же ошибку. –

2

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

for (int a = items_count - 1; a >= 0; --a) 
+1

это нормально, только если у вас есть прямой доступ к элементу коллекции по индексу. –

2

поведения вы видите это by design:

Еогеаспа заявление на языке 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++; 
    } 
} 
1

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

Список элементовTobeRemoved = new List(); для (var i = 0; i < collection.Count; i ++) { if (condition) { itemsTobeRemoved.Add (i); }

Еогеасп (вар я = 0 в itemsTobeRemoved) { , если (условие) { collection.RemoveAt (я); }

Смежные вопросы