编程VB.NET 开发人员

描述 Visual Basic 中循环 For...Each...Next 如何与自定义集合一起工作。如何创建用于 For Each 遍历的自定义集合,以及需要实现什么?

用 Hintsage AI 助手通过面试

答案。

问题的背景:

在 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

关键特性:

  • 需要实现 GetEnumerator 方法并返回 IEnumerator 或 IEnumerator(Of T)。
  • 支持泛型和非泛型 IEnumerable,以与不同版本的环境兼容。
  • 现成的集合可以参与 LINQ、For Each 并与 .NET 的标准基础设施一起工作。

有陷阱的问题。

可以在没有 IEnumerable 接口的情况下实现 For Each,只需写一个 GetEnumerator 方法吗?

不可以,Visual Basic 要求正式支持 IEnumerable/IEnumerable(Of T) 接口,以便编译器识别集合与 For Each 兼容。

枚举器必须是单独的类吗?

不,若元素的数据源支持标准的枚举器(例如,如果您聚合 List(Of T)),可以返回其 GetEnumerator。仅在复杂场景下可能需要自己的 IEnumerator 实现类。

在 For Each 循环中可以修改集合吗?

不可以,在迭代期间修改集合将导致 InvalidOperationException。要正确处理,需要使用特定的策略(例如,在遍历之前复制列表或使用索引)。

常见错误和反模式

  • 仅实现 Add/Remove 而没有 IEnumerable——无法使用 For Each。
  • 返回不存在或不正确的 Enumerator——在遍历时会导致崩溃。
  • 在 For Each 循环体内修改集合。

生活中的例子

负面案例

在公司中开发了一个自定义类 MyCollection,通过数组进行添加和删除,但未实现 IEnumerable 接口。因此 For Each 无法工作,只能使用普通循环和元素的公共字段。

优点:

  • 快速创建集合——代码量最少。

缺点:

  • 无法使用 For Each、LINQ,无法像标准集合一样工作。
  • 在不同地方出现了重复的遍历代码。

正面案例

类被改造成实现 IEnumerable(Of T)。此后,集合可以轻松、标准地用于 For Each,并且与 LINQ 兼容。

优点:

  • 干净、标准的语法。
  • 集合遍历与 VB.NET 的所有基础设施功能兼容。

缺点:

  • 需要添加更多代码来支持接口。