【发布时间】:2016-01-29 12:21:22
【问题描述】:
在这个问题Foreach loop for disposing controls skipping iterations 之后,它让我感到困扰的是,允许对不断变化的集合进行迭代:
例如:
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);
}
抛出
InvalidOperationException:集合已修改;枚举操作可能无法执行。
但是在 .Net 表单中你可以这样做:
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();
}
它跳过元素,因为迭代器在变化的集合上运行,没有抛出异常
错误?如果底层集合发生变化,迭代器是否不需要抛出InvalidOperationException?
所以我的问题是为什么迭代不断变化的ControlCollection 不会抛出 InvalidOperationException?
附录:
documentation for IEnumerator 说:
枚举器没有对集合的独占访问权;因此,通过集合进行枚举本质上不是线程安全的过程。即使集合已同步,其他线程仍然可以修改集合,这会导致枚举器抛出异常。
【问题讨论】:
-
对于其他人来说,this is where 和
Control在被处置时会从父集合中删除。 -
@Serv 但是你没有调用 Control.ControlCollection.Remove() ?
-
@ChrisWohlert 在处置过程中代表您调用/删除了它 - 请参阅我上面评论中的链接。
-
@AmitKumarGhosh 循环遍历已经被释放的子控件。出于所有意图和目的,孩子的父母已经消失,因此在调用孩子 dispose 之前将其设置为 null 是有意义的
-
@AmitKumarGhosh 父级中的代码将子级的父级设置为空。 IE 它正在与自己的孩子分离,因为它已经完成了一半的处置。鉴于发生的一件事是孩子在处置过程中在其父母的孩子集合上调用
Remove,您可能希望首先断开该链接。
标签: c# .net winforms foreach invalidoperationexception