This is something that I was exploring to see if I could take what was
List<MdiChild> openMdiChildren = new List<MdiChild>();
foreach(child in MdiManager.Pages)
{
openMdiChildren.Add(child);
}
foreach(child in openMdiChild)
{
child.Close();
}
and shorten it to not require 2 foreach loops.
Note I’ve changed what the objects are called to simplify this for this example (these come from 3rd party controls). But for information and understanding
MdiManager.Pages inherits form CollectionBase, which in turn inherits IEnumerable
and MdiChild.Close() removes the open child from the MdiManager.Pages Collection, thus altering the collection and causing the enumeration to throw an exception if the collection was modified during enumeration, e.g..
foreach(child in MdiManage.Pages)
{
child.Close();
}
I was able to the working double foreach to
((IEnumerable) MdiManager.Pages).Cast<MdiChild>.ToList()
.ForEach(new Action<MdiChild>(c => c.Close());
Why does this not have the same issues dealing with modifying the collection during enumeration? My best guess is that when Enumerating over the List created by the ToList call that it is actually executing the actions on the matching item in the MdiManager.Pages collection and not the generated List.
Edit
I want to make it clear that my question is how can I simplify this, I just wanted to understand why there weren’t issues with modifying a collection when I performed it as I have it written currently.
Your call to
ToList()is what saves you here, as it’s essentially duplicating what you’re doing above.ToList()actually creates aList<T>(aList<MdiChild>in this case) that contains all of the elements inMdiManager.Pages, then your subsequent call toForEachoperates on that list, not onMdiManager.Pages.In the end, it’s a matter of style preference. I’m not personally a fan of the
ForEachfunction (I prefer the query composition functions likeWhereandToList()for their simplicity and the fact that they aren’t engineered to have side-effects upon the original source, whereasForEachis not).You could also do:
Fundamentally, all three approaches do exactly the same thing (they cache the contents of
MdiManager.Pagesinto aList<MdiChild>, then iterate over that cached list and callClose()on each element.