Following this question Foreach loop for disposing controls skipping iterations it bugged me that iteration was allowed over a changing collection:
For example, the following:
List<Control> items = new List<Control>
{
new TextBox {Text = "A", Top = 10},
new TextBox {Text = "B", Top = 20},
new TextBox {Text = "C", Top = 30},
new TextBox {Text = "D", Top = 40},
};
foreach (var item in items)
{
items.Remove(item);
}
throws
InvalidOperationException: Collection was modified; enumeration operation may not execute.
However in a .Net Form you can do:
this.Controls.Add(new TextBox {Text = "A", Top = 10});
this.Controls.Add(new TextBox {Text = "B", Top = 30});
this.Controls.Add(new TextBox {Text = "C", Top = 50});
this.Controls.Add(new TextBox {Text = "D", Top = 70});
foreach (Control control in this.Controls)
{
control.Dispose();
}
which skips elements because the the iterator runs over a changing collection, without throwing an exception
bug? aren't iterators required to throw InvalidOperationException
if the underlaying collection changes?
So my question is Why does iteration over a changing ControlCollection
NOT throw InvalidOperationException?
Addendum:
The documentation for IEnumerator
says:
The enumerator does not have exclusive access to the collection; therefore, enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads can still modify the collection, which causes the enumerator to throw an exception.
this.Controls.Count
chages after theforeach
is complete? I think the controllCollection itself is not changing. – LibreControl.ControlCollection.Remove()
call – SomethingControl
removes itself from the parent collection when being disposed. – Phagectl.parent = null;
- this is interesting. But how is the parent affected? – LibreRemove
on it's parent's child collection during disposal, you probably want to break that link first. – Phage