大家好我发现了一个我无法逻辑解释的问题。在下面的代码片段中,flpRecordIndexes是一个FlowLayoutPabel,它包含许多RecordIndexControl(我创建的用户控件)。我想删除除第一个控件之外的所有内容。与flpRecordContainer相同的想法。
如果我执行此操作(没有ToList调用),它只删除一半的控件,如果它是一个序列,例如它将删除(2,4,6,8)等。
foreach (var recordIndexControl in flpRecordIndexes.Controls.Cast<RecordIndexControl>().Skip(1))
{
flpRecordIndexes.Controls.Remove(recordIndexControl);
}
foreach (var recordControl in flpRecordContainer.Controls.Cast<RecordControl>().Skip(1))
{
flpRecordContainer.Controls.Remove(recordControl);
}
如果我执行此操作(使用ToList),它将删除除第一个控件之外的所有内容,即我想要的内容。
foreach (var recordIndexControl in flpRecordIndexes.Controls.Cast<RecordIndexControl>().ToList().Skip(1))
{
flpRecordIndexes.Controls.Remove(recordIndexControl);
}
foreach (var recordControl in flpRecordContainer.Controls.Cast<RecordControl>().ToList().Skip(1))
{
flpRecordContainer.Controls.Remove(recordControl);
}
为什么在没有ToList的情况下调用Cast会产生这种行为?
答案 0 :(得分:6)
这是完全正常的,您正在使用Controls.Remove()调用修改正在迭代的集合。 Controls集合的行为与其他框架集合不同,它在执行此操作时不会引发异常。所以实际上你会删除所有其他控件,具体取决于混音。
ToList()调用创建Controls集合的副本,它不再受Remove()调用的影响。这是正确的解决方法。
请记住,你很可能有一个讨厌的泄漏。您删除的控件必须处理。您不能再依赖Winforms为您执行此操作,因为它们不再位于Controls集合中。未能处理它们是永久性泄漏,垃圾收集器无法帮助。
答案 1 :(得分:2)
为什么在没有ToList的情况下调用Cast会产生这种行为?
调用ToList()
实现了集合,而Cast<T>
没有。一旦ToList()
被调用,列表就会固化,所以你在列表中有一个有限的数字。
我建议通过for
循环而不是foreach
来迭代Control.Controls
。这将避免您完全看到的问题,实际上更高效。 ControlCollection
类会继承IList
,因此您应该对此感到满意。
for (var index = Controls.Count - 1; index >= 1; -- index)
{
flpRecordContainer.Controls.RemoveAt(index);
}
请注意index >= 1
以确保我们将第一个控件留在列表中。