class Program
{
static void Main(string[] args)
{
var dictionary = new Dictionary<string, int>()
{
{"1", 1}, {"2", 2}, {"3", 3}
};
foreach (var s in dictionary.Keys)
{
// Throws the "Collection was modified exception..." on the next iteration
// What's up with that?
dictionary[s] = 1;
}
}
}
I completely understand why this exception is thrown when enumerating a list- it seems reasonable to expect that during enumeration, the Structure of the enumerated object does not change. However- does changing a Value of a dictionary changes its Structure? Specifically, the structure of its keys?
Indexer on
Dictionary
is potentially an operation that can change the structure of the collection, since it will add a new entry with such key if one doesn't exist already. This obviously isn't the case here, but I expect thatDictionary
contract is deliberately kept simple in that all operations on the object are divided into "mutating" and "non-mutating", and all "mutating" operations invalidate enumerators, even if they don't actually change anything.From the documentation (Dictionary.Item Property):
So, as John indicates, there is no way for the framework to know that you haven't altered the contents of the list, so it assumes that you have.
It's possible that you've just inserted a new key into the dictionary, which would indeed change
dictionary.Keys
. Even though in this specific loop that will never happen, the[]
operation in general can change the list of keys so this is flagged as a mutation.It's because they designed .Net with the ability to iterate a collection in multiple threads. So you either gotta allow the iterator be multithreaded or prevent that and allow the modification of the collection during the iteration which would require limiting the object to be itereated in a single thread. Can't have both.
In fact the answer to your question is that the code you type in actually results in a compiler generated ([CompilerGenerated]) state machine that allows for iterators to maintain the collection state in order to provide the yield magic. Thats why if you dont synchronize your collections and you iterate in one thread and manipulate in another thread, you;ll get some funky shit going on.
Check out: http://csharpindepth.com/articles/chapter6/iteratorblockimplementation.aspx
Also: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentHashMap.html "iterators are designed to be used by only one thread at a time."
The short answer is that you are modifying the dictionary collection, even though you're not actually changing any of its keys. So the next iteration that accesses the collection after your update throws an exception that indicates that the collection was modified since your last access (and rightly so).
To do what you want, you need a different way of iterating through the elements, so that changing them won't trigger an iterator exception.
Because the values and keys are stored as a pair. There is not a separate structure for keys and values but instead a single structure which stores both as a set of pair values. When you change a value it necessitates changing the single underlying structure which contains both keys and values.
Does changing a value necessarily change the order of the underlying structure? No. But this is an implementation specific detail and the
Dictionary<TKey,TValue>
class, correctly, deemed not to reveal this by allowing modification of values as part of the API.