Почему я получаю "Коллекция была изменена, операция перечисления может не выполняться", когда не изменялась перечисляемая коллекция?
У меня есть две коллекции строк: CollectionA - свойство StringCollection объекта, хранящегося в системе, а CollectionB - это List, сгенерированный во время выполнения. CollectionA необходимо обновить, чтобы соответствовать CollectionB, если есть какие-либо различия. Поэтому я разработал то, что, как я ожидал, был простым методом LINQ для выполнения удаления.
var strDifferences = CollectionA.Where(foo => !CollectionB.Contains(foo));
foreach (var strVar in strDifferences) { CollectionA.Remove(strVar); }
Но я получаю ошибку "Collection was modified; enumeration operation may not execute"
для strDifferences... хотя это отдельная перечислимая из измененной коллекции! Первоначально я разработал это явно, чтобы уклониться от этой ошибки, поскольку моя первая реализация создаст ее (поскольку я перечислял через CollectionA
и просто удалял, когда !CollectionB.Contains(str)
). Может ли кто-нибудь пролить некоторое представление о том, почему это перечисление терпит неудачу?
Ответы
Ответ 1
Эти два не являются полностью отдельными. Where
не создает отдельную копию коллекции. Он внутренне сохраняет ссылку на исходную коллекцию и извлекает из нее элементы по мере их запроса.
Вы можете решить свою проблему, добавив ToList()
, чтобы принудительно выполнить Where
для немедленного итерации коллекции.
var strDifferences = CollectionA
.Where(foo => !CollectionB.Contains(foo))
.ToList();
Ответ 2
Where
возвращает IEnumerable<T>
, а затем вы используете это в foreach (var strVar in strDifferences)
Затем вы пытаетесь удалить его из коллекции, создавшей IEnumerable<T>
. Вы не создали новый список, ссылаясь на CollectionA
, чтобы вытащить следующий элемент, поэтому вы не можете редактировать CollectionA
.
Вы также можете сделать это:
var strDifferences = CollectionA.Where
(foo => CollectionB.Contains(foo)).ToList();
CollectionA = strDifferences;
//or instead of reassigning CollectionA
CollectionA.Clear();
CollectionA.AddRange(strDifferences);
Так как вы удаляете те, которые не находятся в CollectionB. Просто найдите те, которые есть, создайте список и назначьте этот список переменной CollectionA.
Ответ 3
Попробуйте немного изменить первую строку:
var strDifferences =
CollectionA.Where(foo => !CollectionB.Contains(foo)).ToList();
Я думаю, что LINQ использует ленивое выполнение вашего запроса. Вызов ToList
приведет к выполнению запроса до перечисления.