迭代器函数误解概念

Iterator function miss-understanding concept

如果我没记错的话,迭代器函数可以作为一种更快地构建集合的方法,因为它会记住添加最后一项的索引。

现在,有没有办法访问正在构建的集合?

例如,假设我需要在生成一个新元素之前确定集合是否包含一个元素,就像这样(一个非常糟糕的例子):

Public Iterator Function MyFunc(Byval param1 As whatever) As IEnumerable(Of whatever)

    For value As Integer = 0 to whatever

        If Not THE_ITERATOR_COLLECTION.Contains(whatever)
           Yield value
        End If

    End For

End Function

这可能吗?

No, you cannot access the auto generated iterator at design-time.

Iterator 关键字提供了一种无需实际创建迭代器即可快速简便地创建迭代器的方法。它由编译器创建(基于迭代器 function/property),因此在设计时不可用。您必须创建自定义迭代器或重新考虑您的设计。

看看这个简单的迭代器函数。

Public Iterator Function Foo() As IEnumerable(Of Char)
    Yield "H"c
    Yield "E"c
    Yield "L"c
    Yield "L"c
    Yield "O"c
End Function

上面的函数编译成如下所示的函数。自动生成的迭代器的类型命名为 VB$StateMachine_0_Foo.

Public Function Foo() As IEnumerable(Of Char)
    Dim $sm As New VB$StateMachine_0_Foo
    $sm.$VB$Me = Me
    $sm.$State = -2
    Return $sm
End Function

迭代器的内部工作原理没有什么特别之处。它的工作方式与任何其他精心设计的迭代器相同。

<CompilerGenerated> _
Private NotInheritable Class VB$StateMachine_0_Foo
    Implements IDisposable, IEnumerator, IEnumerator(Of Char), IEnumerable, IEnumerable(Of Char)

    <DebuggerNonUserCode> _
    Private Overrides Function GetEnumerator() As IEnumerator(Of Char) Implements IEnumerable(Of Char).GetEnumerator
        If ((Thread.CurrentThread.ManagedThreadId = Me.$InitialThreadId) AndAlso (Me.$State = -2)) Then
            Me.$State = -1
            Return Me
        End If
        Dim foo As New VB$StateMachine_0_Foo
        foo.$VB$Me = Me.$VB$Me
        Return foo
    End Function

    <DebuggerNonUserCode> _
    Private Overrides Function GetEnumerator0() As IEnumerator Implements IEnumerable.GetEnumerator
        Return Me.GetEnumerator
    End Function

    <CompilerGenerated> _
    Friend Overrides Function MoveNext() As Boolean Implements IEnumerator.MoveNext
        Dim VB$doFinallyBodies As Boolean = True
        Try
            Select Case Me.$State
                Case 0
                    If Not Me.$Disposing Then
                        GoTo Label_0066
                    End If
                    Return False
                Case 1
                    If Not Me.$Disposing Then
                        GoTo Label_0099
                    End If
                    Return False
                Case 2
                    If Not Me.$Disposing Then
                        GoTo Label_00CC
                    End If
                    Return False
                Case 3
                    If Not Me.$Disposing Then
                        GoTo Label_00F9
                    End If
                    Return False
                Case 4
                    If Not Me.$Disposing Then
                        GoTo Label_0126
                    End If
                    Return False
                Case 5
                    Exit Select
                Case Else
                    If Not Me.$Disposing Then
                        GoTo Label_0039
                    End If
                    Exit Select
            End Select
            Return False
Label_0039:
            Me.$Current = "H"c
            Me.$State = 0
            VB$ doFinallyBodies = False
            Return True
Label_0066:
            Me.$State = -1
            Me.$Current = "E"c
            Me.$State = 1
            VB$ doFinallyBodies = False
            Return True
Label_0099:
            Me.$State = -1
            Me.$Current = "L"c
            Me.$State = 2
            VB$ doFinallyBodies = False
            Return True
Label_00CC:
            Me.$State = -1
            Me.$Current = "L"c
            Me.$State = 3
            VB$ doFinallyBodies = False
            Return True
Label_00F9:
            Me.$State = -1
            Me.$Current = "O"c
            Me.$State = 4
            VB$ doFinallyBodies = False
            Return True
Label_0126:
            Me.$State = -1
        Catch exception1 As Exception
            ProjectData.SetProjectError(exception1)
            Dim $ex As Exception = exception1
            Me.$State = 5
            Throw
            ProjectData.ClearProjectError()
        End Try
        Me.$State = 5
        Return False
    End Function

    <DebuggerNonUserCode> _
    Private Overrides Sub System.Collections.IEnumerator.Reset() Implements IEnumerator.Reset
        Throw New NotSupportedException
    End Sub

    <DebuggerNonUserCode> _
    Private Overrides Sub System.IDisposable.Dispose() Implements IDisposable.Dispose
        Me.$Disposing = True
        Me.MoveNext()
        Me.$State = 5
    End Sub

    Private Overrides ReadOnly Property System.Collections.Generic.IEnumerator(Of Char).Current As Char
        <DebuggerNonUserCode> _
        Get
            Return Me.$Current
        End Get
    End Property

    Private Overrides ReadOnly Property System.Collections.IEnumerator.Current As Object
        <DebuggerNonUserCode> _
        Get
            Return Me.$Current
        End Get
    End Property

    Friend $Current As Char
    Friend $Disposing As Boolean
    Friend $InitialThreadId As Integer = Thread.CurrentThread.ManagedThreadId
    Friend $State As Integer = -1
    Friend $VB$Me As Form1

End Class

相关参考资料: