VB.NET中的迭代器模式(C#将使用yield!)

时间:2008-10-30 16:43:53

标签: vb.net design-patterns iterator yield

如何在VB.NET中实现迭代器模式,该模式没有yield关键字?

6 个答案:

答案 0 :(得分:15)

现在,VS 2010 SP1支持使用Async CTP,请参阅:Iterators (C# and Visual Basic) on MSDNdownload Visual Studio Async CTP (Version 3)

这样的代码,有效:

Private Iterator Function SomeNumbers() As IEnumerable
    ' Use multiple yield statements.
    Yield 3
    Yield 5
    Yield 8
End Function

答案 1 :(得分:2)

VB.NET不支持创建自定义迭代器,因此没有与C#yield关键字等效的东西。但是,您可能需要查看知识库文章 How to make a Visual Basic .NET or Visual Basic 2005 class usable in a For Each statement 以获取更多信息。

答案 2 :(得分:1)

嗯,看起来你可能是out of luck

  

今天在将一些C#转换为VB.NET时我遇到了一个问题。 C#有一个非常酷的“yield return”语句,它在迭代器块中用于为枚举器对象提供值。 VB.NET没有“yield”关键字。因此,有一些解决方案(其中没有一个真的很干净)来解决这个问题。如果循环并且想要破坏枚举器并返回单个值,则可以使用return语句返回值。但是,如果要返回整个枚举,请创建子类型的List()并返回列表。由于您通常使用IEnumerable,因此List()将很好用。

这是一年前写的,不知道从那以后有没有人能想出更好的东西..


编辑:这将在VB.NET的版本11(VS2010之后的版本)中实现,计划支持迭代器。规范is available here

答案 3 :(得分:1)

C#的yield关键字强制编译器在后台创建一个状态机来支持它。 VB.Net没有yield关键字。但它确实有一个允许您在函数中创建状态机的构造:Static function members

应该可以通过创建实现IEnumerable的泛型类以及所需的状态机并将实例作为静态成员放在函数内来模仿yield return函数的效果。

当然,这需要在函数之外实现类。但如果做得好,这个类应该可以在一般情况下重复使用。但是,我没有充分利用这个想法来提供任何实现细节。

答案 4 :(得分:0)

请记住,LINQ表达式和方法的延迟执行和延迟求值属性允许我们有效地实现自定义迭代器,直到.NET 4.5中的yield语句可用。 Yield由LINQ表达式和方法在内部使用。

以下代码演示了这一点。

    Private Sub AddOrRemoveUsersFromRoles(procName As String,
                                      applicationId As Integer,
                                      userNames As String(),
                                      rolenames As String())
    Dim sqldb As SqlDatabase = CType(db, SqlDatabase)
    Dim command As DbCommand = sqldb.GetStoredProcCommand(procName)
    Dim record As New SqlDataRecord({New SqlMetaData("value", SqlDbType.VarChar,200)})
    Dim setRecord As Func(Of String, SqlDataRecord) =
        Function(value As String)
            record.SetString(0, value)
            Return record
        End Function
    Dim userNameRecords As IEnumerable(Of SqlDataRecord) = userNames.Select(setRecord)
    Dim roleNameRecords As IEnumerable(Of SqlDataRecord) = rolenames.Select(setRecord)
    With sqldb
        .AddInParameter(command, "userNames", SqlDbType.Structured, userNameRecords)
        .AddInParameter(command, "roleNames", SqlDbType.Structured, roleNameRecords)
        .AddInParameter(command, "applicationId", DbType.Int32, applicationId)
        .AddInParameter(command, "currentUserName", DbType.String, GetUpdatingUserName)
        .ExecuteNonQuery(command)
    End With
End Sub

答案 5 :(得分:-4)

下面给出输出:2,4,8,16,32

在VB.NET中

Public Shared Function setofNumbers() As Integer()

    Dim counter As Integer = 0
    Dim results As New List(Of Integer)
    Dim result As Integer = 1
    While counter < 5
        result = result * 2
        results.Add(result)
        counter += 1
    End While
    Return results.ToArray()
End Function

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    For Each i As Integer In setofNumbers()
        MessageBox.Show(i)
    Next
End Sub

在C#中

private void Form1_Load(object sender, EventArgs e)
{
    foreach (int i in setofNumbers())
    {
        MessageBox.Show(i.ToString());
    }
}

public static IEnumerable<int> setofNumbers()
{
    int counter=0;
    //List<int> results = new List<int>();
    int result=1;
    while (counter < 5)
    {
      result = result * 2;
      counter += 1;
      yield return result;
    }
}