Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why am I getting "Collection was modified; enumeration operation may not execute" when not modifying the enumerated collection? [duplicate]

I have two collections of strings: CollectionA is a StringCollection property of an object stored in the system, while CollectionB is a List generated at runtime. CollectionA needs to be updated to match CollectionB if there are any differences. So I devised what I expected to be a simple LINQ method to perform the removal.

var strDifferences = CollectionA.Where(foo => !CollectionB.Contains(foo));
foreach (var strVar in strDifferences) { CollectionA.Remove(strVar); }

But I am getting a "Collection was modified; enumeration operation may not execute" error on strDifferences... even though it is a separate enumerable from the collection being modified! I originally devised this explicitly to evade this error, as my first implementation would produce it (as I was enumerating across CollectionA and just removing when !CollectionB.Contains(str)). Can anyone shed some insight into why this enumeration is failing?

like image 276
Grace Note Avatar asked May 07 '10 20:05

Grace Note


People also ask

What is enumeration operation may not execute?

Why the error Collection was modified; enumeration operation may not execute occurs and how to handle it in C#? CsharpServer Side ProgrammingProgramming. This error occurs when a looping process is being running on a collection (Ex: List) and the collection is modified (data added or removed) during the runtime.


3 Answers

The two are not completely separate. Where does not make a separate copy of the collection. It internally keeps a reference to the original collection and fetches elements from it as you request them.

You can solve your problem by adding ToList() to force Where to iterate through the collection immediately.

var strDifferences = CollectionA
    .Where(foo => !CollectionB.Contains(foo))
    .ToList();
like image 74
Mark Byers Avatar answered Sep 23 '22 20:09

Mark Byers


Where passes back IEnumerable<T> and then you are using that in your foreach (var strVar in strDifferences)

You are then trying to remove it from the collection that created the IEnumerable<T>. You haven't created a new list, it's referencing CollectionA to pull the next item from, so you can't edit CollectionA.

You can do this also:

var strDifferences = CollectionA.Where
  (foo => CollectionB.Contains(foo)).ToList();

CollectionA = strDifferences;
//or instead of reassigning CollectionA
CollectionA.Clear();
CollectionA.AddRange(strDifferences);

Since you are removing the ones that aren't in CollectionB. Just look for the ones that are, create a list and assign that list to the CollectionA variable.

like image 36
kemiller2002 Avatar answered Sep 24 '22 20:09

kemiller2002


Try modifying the first line a bit:

var strDifferences =
    CollectionA.Where(foo => !CollectionB.Contains(foo)).ToList();

I think LINQ is using lazy execution of your query. The call to ToList will force execution of the query prior to enumerating.

like image 36
Justin Niessner Avatar answered Sep 23 '22 20:09

Justin Niessner