问题背景
迭代器自编程语言中出现集合后,成为了一个重要组成部分,这些集合需要被遍历。从 .NET 版本开始,Visual Basic 支持 IEnumerable/IEnumerator,使得创建自定义可枚举集合成为可能,并能够使用 For Each 循环以便捷和简洁的方式访问集合内容。
问题
许多开发者仅使用内置集合,或未正确实现 IEnumerable 接口,从而无法通过 For Each 遍历对象。此外,通过 Current 和 MoveNext 实现和维护迭代器状态也较为复杂。
解决方案
为支持迭代,类型实现 IEnumerable 接口(或泛型 IEnumerable(Of T))。实现 GetEnumerator 函数以返回实现了 IEnumerator 的对象。在 VB.NET 中,还可以使用 Yield 关键字实现迭代器方法(从 VB 2015 开始),这大大简化了遍历的实现。
代码示例:
Imports System.Collections Public Class SimpleCollection Implements IEnumerable Private arr() As Integer = {1, 2, 3} Public Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator For Each i In arr Yield i ' 针对 VB 2015+ Next End Function End Class ' 使用: For Each n As Integer In New SimpleCollection() Console.WriteLine(n) Next
关键特性:
支持 For Each 是否必须同时实现两个接口:IEnumerable 和 IEnumerator?
不,足够实现 IEnumerable 并返回兼容的迭代器。如果您想实现遍历,可以使用嵌套集合中已有的 IEnumerator。但是,完全自定义实现需要两个部分的实现。
代码示例:
Public Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator Return arr.GetEnumerator() ' 使用内置数组迭代器 End Function
在 Visual Basic 中是否可以仅显式实现 IEnumerable?
是的,您可以显式实现接口,特别是在您的集合已经有自己的 GetEnumerator,并且您希望隐藏接口的实现时。无法直接调用这样的 GetEnumerator,但 For Each 可以正常工作。
代码示例:
Public Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator ' ...方法体 End Function
如果 GetEnumerator 返回 Nothing,会发生什么?
在首次尝试遍历集合时将抛出异常,因为 For Each 期望有效的迭代器。
集合类未实现 IEnumerable,而单独创建了 Next 方法来遍历元素。因此,它无法在通用方法或 For Each 中使用,需要编写额外的方法。
优点:
缺点:
开发者实现了 IEnumerable 和 GetEnumerator,现在集合可以与 For Each 一起使用,并与 LINQ 集成。
优点:
缺点: