views:

136

answers:

4

Hello,

first i must assume that i'm not very familiar with the C# yield keyword and its function. What is the best/easiest way to "translate" it into VB.NET? Especially i tried to convert this code into VB.NET, but i failed with:

yield return new MatchNode(++index, current.Value);

What i have is:

Imports System.Collections
Imports System.Data.SqlTypes
Imports System.Diagnostics.CodeAnalysis
Imports System.Text.RegularExpressions
Imports Microsoft.SqlServer.Server

Class MatchNode
    Private _index As Integer
    Private _value As String

    Public Sub New(ByVal index As Integer, ByVal value As String)
        _index = index
        _value = value
    End Sub

    Public ReadOnly Property Index() As Integer
        Get
            Return _index
        End Get
    End Property

    Public ReadOnly Property Value() As String
        Get
            Return _value
        End Get
    End Property

End Class

Class MatchIterator
    Implements IEnumerable

    Private _regex As Regex
    Private _input As String

    Public Sub New(ByVal input As String, ByVal pattern As String)
        MyBase.New()
        _regex = New Regex(pattern, UserDefinedFunctions.Options)
        _input = input
    End Sub

    Public Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
        Dim index As Integer = 0
        Dim current As Match = Nothing

        While (current Is Nothing OrElse current.Success)
            If current Is Nothing Then
                current = _regex.Match(_input)
            Else
                current = current.NextMatch()
            End If

            If current.Success Then
                index += 1
                'following should be a VB.Net yield'
                Return New MatchNode(index, current.Value)
            End If

        End While
    End Function
End Class

Partial Public Class UserDefinedFunctions

    <SqlFunction(FillRowMethodName:="FillMatchRow", TableDefinition:="[Index] int,[Text] nvarchar(max)")> _
    Public Shared Function RegexMatches(ByVal input As SqlChars, ByVal pattern As SqlString) As IEnumerable
        Return New MatchIterator(New String(input.Value), pattern.Value)
    End Function

    Public Shared Sub FillMatchRow(ByVal data As Object, ByRef index As SqlInt32, ByRef text As SqlChars)
        Dim node As MatchNode = CType(data, MatchNode)
        index = New SqlInt32(node.Index)
        text = New SqlChars(node.Value.ToCharArray)
    End Sub

End Class
+3  A: 

Since VB.NET doesn't provide iterator blocks, you will have to write the iterator class by hand, which is extremely painful. I'll try to write it (manually) in C# for you, so you can see what I mean... like so:

internal class MatchIterator : IEnumerable
{
    private class MatchEnumerator : IEnumerator
    {
        int index = 0;
        private Match currentMatch;
        private MatchNode current;
        readonly Regex regex;
        readonly string input;
        public MatchEnumerator(Regex regex, string input)
        {
            this.regex = regex;
            this.input = input;
        }
        public object Current { get { return current; } }

        public void Reset() { throw new NotSupportedException(); }
        public bool MoveNext()
        {
            currentMatch = (currentMatch == null) ? regex.Match(input) : currentMatch.NextMatch();
            if (currentMatch.Success)
            {
                current = new MatchNode(++index, currentMatch.Value);
                return true;
            }
            return false;
        }
    }
    private Regex _regex;
    private string _input;

    public MatchIterator(string input, string pattern)
    {
        _regex = new Regex(pattern, UserDefinedFunctions.Options);
        _input = input;
    }

    public IEnumerator GetEnumerator()
    {
        return new MatchEnumerator(_regex, _input);
    }
}
Marc Gravell
Thanks. I have still the problem that the sql-server returns always an empty result set with this function. But instead of spending more time on converting C# to VB.Net, i will follow Tim Murphy's advice to leave it as C#.
Tim Schmelter
+1  A: 

If you really, really want to implement the iterator class by hand, i recommend reading this chapter of "c# in depth" by Jon Skeet first to get an idea what the c#-compiler does with this little yield keyword.

dkson
I hoped that there would be a similar and simple approach what does nearly the same but without the whole yield-functionality(lazy evaluation).
Tim Schmelter
+2  A: 

You have to ask yourself am I really going to edit this code? If the answer is no or not very much then don't bother, leave it as C# code.

I'm a VB.NET developer and have next to given up on converting C# code from the net into VB.NET. I simply have a C# library for the required project that I dump code into. It is only if I find I need to regularly/heavily develop the code that I go through the pain of converting it to VB.NET.

Tim Murphy
Good point as i am not really needing it as VB.Net but only the dll in SQL-Server.
Tim Schmelter
A: 

There's this nice article by Bill McCarthy in Visual Studio magazine on emulating yield in VB.NET by implementing IEnumerable(Of T) and IEnumerator(Of T).

MarkJ