发生了什么:您正在遍历表单(或继承的另一个类 Control
)的控件集合。
每次调用 Dispose()
它的一个成员时,都会主动将其从集合中删除,因此您正在修改正在迭代的集合。
当你处理第一个控件时,它将从集合中删除,并且列表中的下一个控件 将取代它 .
您的循环调用 Enumerator.MoveNext()
,因此当您 Dispose()
再次调用时,您将处理索引 1 处的元素,该元素之前是索引 2 处的元素。
跳过索引 1 处现在索引 0 处的元素。
这个过程一直持续,结果是你处理掉了集合中一半的控件。
你可以使用以下方法测试它:
For Each ctrl As Control In Me.Controls
ctrl.Dispose()
Console.WriteLine(Me.Controls.Count)
Next
您会发现最终计数是初始计数的一半:一半的控件仍然活跃。
您可以使用向后 For
循环(从 [Collection].Count - 1
到 0
),从集合的顶部开始。
在这种情况下,当您处理控件时,集合会从顶部调整大小,因此 Enumerator.MovePrevious()
不会跳过集合中的任何元素。
For i As Integer = Me.Controls.Count - 1 To 0 Step -1
Me.Controls(i).Dispose()
Next
您还可以使用正向循环并在索引 0 处进行处理。当索引 0 处的元素被处理后,下一个元素将在该索引处取代它的位置,因此您不会跳过任何元素。不过,在这种情况下,集合中的元素会不断 向底部 ,因此这是一个相当缓慢的过程。
如果收藏品数量较少,您可能不会注意到,但请牢记这一点。
For i As Integer = 0 To Me.Controls.Count - 1
Me.Controls(0).Dispose()
Next
您还可以过滤控件集合,以便仅考虑特定的类型。
例如,要处置 Form 的所有 TextBox 控件子项(或从 Control 派生的任何其他类):
Dim textBoxes = Me.Controls.OfType(Of TextBox).ToList()
For i As Integer = textBoxes.Count - 1 To 0 Step -1
textBoxes(i).Dispose()
Next