How to Deal With “Collection was modified; enumeration operation may not execute.” Error

When performing operations on collections, you may get the following exception: “Collection was modified; enumeration operation may not execute.” You will get this error if you are adding to and removing items from a collection in loops and, surprisingly, when modifying items in a Dictionary. Consider an example where we want to fetch and store budgets for each day in a given month and year from a database and if a budget is not there, we store it as null. Assume the GetBudgets(int month, int year, Dictionary) will populate the collection accordingly.

var budgets = new Dictionary<int, decimal?>();
GetBudgets(DateTime.Today.Month, DateTime.Today.Year, budgets);

Let’s say we then want to assign a default budget of 100 if we don’t have it in the database:

foreach (var day in budgets.Keys.Where(budget => budget == null))
{
	budgets[day] = 100;
}

If you run the code above, you will get the “Collection was modified; enumeration operation may not execute.” error. The reason is that the collection is being modified during the enumeration and the IEnumerator that the underlying collection uses exposes the read-only Current property.
To solve this you can simply duplicate the key collection:

foreach (var day in new List<int>(budgets.Keys).Where(budget => budget == null))
{
	budgets[day] = 100;
}

Furthermore, if you have to perform such operations on collections quite often, I would suggest creating an extension method, similar to this:

public static void ChangeNullToDefault(this Dictionary<K, V> dict, V defaultValue)
{
	foreach (K key in new List<K>(dict.Keys).Where(value => value == null))
	{
		dict[key] = defaultValue;
	}
}

For the example above, you can then use

var budgets = new Dictionary<int, decimal?>();
GetBudgets(DateTime.Today.Month, DateTime.Today.Year, budgets);
budgets.ChangeNullToDefault(100);

Have fun!

This entry was posted in C# and tagged , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *