This seems like it should be answered but potential dupes I found were asking different things…
I noticed that this seems to work fine (sourceDirInclusion is a simple Dictionary<X,Y>)
foreach (string dir in sourceDirInclusion.Keys)
{
if (sourceDirInclusion[dir] == null)
sourceDirInclusion.Remove(dir);
}
Does that mean removing items from a collection in foreach is safe, or that I got lucky?
What about if I was adding more elements to the dictionary rather than removing?
The problem I’m trying to solve is that sourceDirInclusion is initially populated, but then each value can contribute new items to the dictionary in a second pass. e.g what I want to do is like:
foreach (string dir in sourceDirInclusion.Keys)
{
X x = sourceDirInclusion[dir];
sourceDirInclusion.Add(X.dir,X.val);
}
Short answer: This is not safe.
Long answer: From the
IEnumerator<T>documentation:Note that the docs say the behavior is undefined, which means that it might work and it might not. One should never rely on undefined behavior.
In this case, it depends on the behavior of the
Keysenumerable, regarding whether or not it creates a copy of the list of keys when you begin enumerating. In this specific case, we know from the docs that the return value fromDictionary<,>.Keysis a collection that refers back to the dictionary:So it should be considered unsafe to modify the dictionary while enumerating the dictionary’s keys.
You can correct this with one change. Alter this line:
To this:
The
ToList()extension method will create an explicit copy of the list of keys, making it safe to modify the dictionary; the “underlying collection” will be the copy and not the original.