C # Modifying IEnumerable when enumerated with ForEach

This is what I studied to see if I can 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 so it doesn't take 2 foreach .

Note I changed what are called to simplify this object for this example (they come from third-party controls). But for information and understanding, MdiManager.Pages inherits a CollectionBase form, which in turn inherits IEnumerable

and MdiChild.Close() removes the open child from the MdiManager.Pages collection, thereby modifying the collection and causing the enumeration to throw an exception if the collection was modified during the enumeration, for example.

 foreach(child in MdiManage.Pages) { child.Close(); } 

I managed to work with double foreach before

 ((IEnumerable) MdiManager.Pages).Cast<MdiChild>.ToList() .ForEach(new Action<MdiChild>(c => c.Close()); 

Why doesn’t it have the same problems with changing the collection during enumeration? My best guess is that when enumerating over a list created by ToList, it is invoked that it actually performs actions in the corresponding element in the MdiManager.Pages collection, and not in the generated list.

Edit

I want to make it clear that my question is how I can simplify this, I just wanted to understand why there were no problems with changing the collection when I executed it, as I wrote it now.

+4
source share
5 answers

Your ToList() call is what saves you, as it essentially duplicates what you do above. ToList() actually creates a List<T> (a List<MdiChild> in this case) that contains all the elements in MdiManager.Pages , then your next call to ForEach works on this list, not on MdiManager.Pages .

In the end, it is a matter of style preference. I personally am not a fan of the ForEach function (I prefer query composition functions like Where and ToList() , for their simplicity and the fact that they are not designed to have side effects on the original source, while ForEach not).

You can also do:

 foreach(child in MdiManager.Pages.Cast<MdiChild>().ToList()) { child.Close(); } 

Basically, all three approaches do the same (they cache the contents of MdiManager.Pages in a List<MdiChild> , then List<MdiChild> over this cached list and call Close() for each element.

+8
source

You are basically right.

ToList() creates a copy of the enumeration, and so you enumerate the copy.

You can also do this, which is equivalent, and shows what you are doing:

 var copy = new List<MdiChild>(MdiManager.Pages.Cast<MdiChild>()); foreach(var child in copy) { child.Close(); } 

Since you are listing copy enumeration elements, you don’t have to worry about changing the Pages collection, since every referece object that exists in the Pages collection now also exists in copy and changes to Pages do not affect it.

All other calling methods, ForEach() and casts are redundant and can be eliminated.

0
source

At first glance, the culprit is ToList (), which is a method that returns a copy of elements in a list, thereby circumventing the problem.

0
source

When you call the ToList() method, you actually enumerate MdiManager.Pages and create a List<MdiChild> right there (so your foreach No. 1). Then, when the ForEach() method is executed, it will list the List<MdiChild> created earlier and take your action for each element (so foreach loop # 2).

So, essentially, this is a different way to accomplish the same thing, simply using LINQ.

0
source

You can also write it as:

 foreach(var page in MdiManager.Pages.Cast<MdiChild>.ToList()) page.Close(); 

Anyway, when you call the ToList () extension method in IEnumerable; you create a new list. Deleted from its original collection (in this case MdiManager.Pages) will not affect the output of the ToList () list.

The same method can be used to remove items from the original collection without worrying about the effect on the source that can be listed.

0
source

Source: https://habr.com/ru/post/1343236/


All Articles