迭代器函数误解概念
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
相关参考资料:
如果我没记错的话,迭代器函数可以作为一种更快地构建集合的方法,因为它会记住添加最后一项的索引。
现在,有没有办法访问正在构建的集合?
例如,假设我需要在生成一个新元素之前确定集合是否包含一个元素,就像这样(一个非常糟糕的例子):
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
相关参考资料: