.NET 4.0中Iterator/Yield等效实现方案咨询(VS2010兼容)
.NET 4.0下VB迭代器(Iterator/Yield)的替代实现
VB的Iterator修饰符和Yield关键字是VB 11(对应Visual Studio 2012)才新增的特性,VS2010(VB 10)和.NET Framework 4.0不支持这些语法,所以需要手动实现迭代器逻辑来替代。以下是两种可行的解决方案:
方案1:手动实现延迟加载迭代器(与原Yield行为一致)
这种方式完全模拟原代码的延迟加载特性,仅在遍历到节点时才生成对应实例,适合节点数量较多的场景,避免一次性占用过多内存。我们通过栈来处理递归遍历逻辑,实现IEnumerable(Of Node)和IEnumerator(Of Node)接口:
Private Shared Function AllNodes(ByVal nodes As NodeCollection) As IEnumerable(Of Node) Return New NodeEnumerable(nodes) End Function Private Class NodeEnumerable Implements IEnumerable(Of Node) Private ReadOnly _rootNodes As NodeCollection Public Sub New(rootNodes As NodeCollection) _rootNodes = rootNodes End Sub Public Function GetEnumerator() As IEnumerator(Of Node) Implements IEnumerable(Of Node).GetEnumerator Return New NodeEnumerator(_rootNodes) End Function Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator Return GetEnumerator() End Function End Class Private Class NodeEnumerator Implements IEnumerator(Of Node) Private ReadOnly _stack As Stack(Of IEnumerator(Of Node)) Private _current As Node Public Sub New(rootNodes As NodeCollection) _stack = New Stack(Of IEnumerator(Of Node))() _stack.Push(rootNodes.GetEnumerator()) End Sub Public ReadOnly Property Current As Node Implements IEnumerator(Of Node).Current Get Return _current End Get End Property Private ReadOnly Property IEnumerator_Current As Object Implements IEnumerator.Current Get Return Current End Get End Property Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext Do While _stack.Count > 0 Dim currentEnumerator = _stack.Peek() If currentEnumerator.MoveNext() Then _current = DirectCast(currentEnumerator.Current, Node) ' 先压入子节点枚举器,保证先返回当前节点,再遍历子节点 If _current.Nodes.Count > 0 Then _stack.Push(_current.Nodes.GetEnumerator()) End If Return True Else ' 当前枚举器遍历完成,释放并弹出 currentEnumerator.Dispose() _stack.Pop() End If Loop Return False End Function Public Sub Reset() Implements IEnumerator.Reset Throw New NotSupportedException("Reset操作不被支持") End Sub Public Sub Dispose() Implements IDisposable.Dispose ' 释放所有栈中剩余的枚举器 While _stack.Count > 0 Dim enumerator = _stack.Pop() enumerator.Dispose() End While End Sub End Class
方案2:预收集所有节点(实现简单,非延迟加载)
如果你的节点数量不多,不需要延迟加载,可以直接递归收集所有节点到列表中,实现起来更简单:
Private Shared Function AllNodes(ByVal nodes As NodeCollection) As IEnumerable(Of Node) Dim nodeList As New List(Of Node)() For Each node As Node In nodes nodeList.Add(node) ' 递归添加子节点 If node.Nodes.Count > 0 Then nodeList.AddRange(AllNodes(node.Nodes)) End If Next Return nodeList End Function
注意事项
- 方案1的延迟加载特性和原
Yield代码完全一致,遍历过程中才会逐个生成节点,适合大数据量场景。 - 方案2会一次性把所有节点加载到内存中,实现成本低,但内存占用较高,适合小数据量场景。
内容的提问来源于stack exchange,提问作者Frank Holloway
相关产品推荐
相关产品推荐

