I know it's been a while since you asked the question, but I was having the same problem of not having a 'yield' keyword in VB. This is what I found and have been using in its stead. You can implement 'yield' with a GenericIterator, here is code for such an Iterator:
Public Class GenericIterator(Of T)
Implements IEnumerable(Of T)
Implements IEnumerator(Of T)
Public Delegate Function MoveNextFunc(ByRef nextItem As T) As Boolean
Private _Current As T
Private _func As MoveNextFunc
Public Sub New(ByVal func As MoveNextFunc)
_func = func
End Sub
Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
Return _func(_Current)
End Function
Public Function GetEnumerator() As IEnumerator(Of T) Implements IEnumerable(Of T).GetEnumerator
Static iBeenCalled As Int32
If (iBeenCalled = 0) AndAlso _
(Threading.Interlocked.Increment(iBeenCalled) = 1) Then
Return Me
Else
Return New GenericIterator(Of T)(_func)
End If
End Function
Public ReadOnly Property Current() As T Implements IEnumerator(Of T).Current
Get
Return _Current
End Get
End Property
Public Overridable Sub Reset() Implements IEnumerator.Reset
Throw New NotImplementedException("Iterator cannot be reset")
End Sub
Private Function IEnumerator_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
Return Me.GetEnumerator
End Function
Private ReadOnly Property IEnumerator_Current() As Object Implements IEnumerator.Current
Get
Return Me.Current
End Get
End Property
Public Sub Dispose() Implements IDisposable.Dispose
' not implemented
End Sub
End Class
Once you have this class you can implement 'yield' similar to how it's done in this sample Zip extension function:
Public Module IEnumerableExtensions
<Extension()>
Public Function Zip(Of T1, T2)(ByVal left As IEnumerable(Of T1), ByVal right As IEnumerable(Of T2)) As IEnumerable(Of Pair(Of T1, T2))
Dim leftG As IEnumerator(Of T1) = left.Select(Function(x) x).GetEnumerator()
Dim rightG As IEnumerator(Of T2) = right.Select(Function(x) x).GetEnumerator()
Return New GenericIterator(Of Pair(Of T1, T2)) _
(Function(ByRef x) As Boolean
Dim canMove As Boolean = leftG.MoveNext() AndAlso rightG.MoveNext()
x = New Pair(Of T1, T2)(leftG.Current, rightG.Current)
Return canMove
End Function)
End Function
End Module
The lambda function has a single by ref parameter which you are supposed to save your return value to.
It is worth noting that I called the selects on leftG and rightG because the compiler was complaining about how some IEumerables like {"foo", "bar"} had already materialized. The select calls naturally removed the materialization.
It is also worth noting that for the extension function to work properly you need to import System.Runtime.CompilerServices
. For the Iterator you need System.Collections.Generic
. And in general you obviously need System.Linq
.
It is also worth noting that in the above function 'Pair' is:
Public Class Pair(Of T1, T2)
Public Property First As T1
Public Property Second As T2
Public Sub New(ByVal f As T1, ByVal s As T2)
First = f
Second = s
End Sub
End Class
I hope this helps your conversion efforts in some way! Good luck!