问题的背景:
在 Visual Basic 中,For Each...Next 操作符允许遍历集合或数组的元素。从 VB6 开始,支持对标准集合的遍历,而在 VB.NET 中,支持遍历所有实现了特定接口的类型。但是,当需要创建自定义集合以供自身遍历时,正确实现所需的基础设施是至关重要的。
问题
仅实现元素存储是不够的——For Each 操作符要求支持专用接口 IEnumerable。自定义集合的程序集常常仅限于 Add/Get 方法,导致对象变成了遍历的“黑匣子”。这妨碍了与遍历语言结构的集成,并导致错误。
解决方案
为了确保 For Each 正确地与您的集合一起工作,需要实现 IEnumerable 接口,而为了支持与泛型元素的工作,需要实现 IEnumerable(Of T)。还需要创建自己的枚举器 (Enumerator),实现 IEnumerator 接口(或在泛型版本中实现 IEnumerator(Of T))。
示例:
Public Class IntCollection Implements IEnumerable(Of Integer) Private ReadOnly items As New List(Of Integer)() Public Sub Add(value As Integer) items.Add(value) End Sub Public Function GetEnumerator() As IEnumerator(Of Integer) _ Implements IEnumerable(Of Integer).GetEnumerator Return items.GetEnumerator() End Function Private Function IEnumerable_GetEnumerator() As IEnumerator _ Implements IEnumerable.GetEnumerator Return GetEnumerator() End Function End Class ' 使用: Dim col As New IntCollection() col.Add(10) col.Add(20) col.Add(30) For Each n As Integer In col Console.WriteLine(n) Next
关键特性:
可以在没有 IEnumerable 接口的情况下实现 For Each,只需写一个 GetEnumerator 方法吗?
不可以,Visual Basic 要求正式支持 IEnumerable/IEnumerable(Of T) 接口,以便编译器识别集合与 For Each 兼容。
枚举器必须是单独的类吗?
不,若元素的数据源支持标准的枚举器(例如,如果您聚合 List(Of T)),可以返回其 GetEnumerator。仅在复杂场景下可能需要自己的 IEnumerator 实现类。
在 For Each 循环中可以修改集合吗?
不可以,在迭代期间修改集合将导致 InvalidOperationException。要正确处理,需要使用特定的策略(例如,在遍历之前复制列表或使用索引)。
在公司中开发了一个自定义类 MyCollection,通过数组进行添加和删除,但未实现 IEnumerable 接口。因此 For Each 无法工作,只能使用普通循环和元素的公共字段。
优点:
缺点:
类被改造成实现 IEnumerable(Of T)。此后,集合可以轻松、标准地用于 For Each,并且与 LINQ 兼容。
优点:
缺点: