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

13

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

6个回答

17

2

1

嗯,看起来你可能运气不太好:

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

这是一年前写的,不确定是否有人在那时候提出了更好的解决方案。


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


1

C# 的 yield 关键字会强制编译器在后台创建一个状态机来支持它。VB.Net 没有 yield 关键字,但它有一种构造方式可以让你在函数内部创建一个状态机:静态函数成员

通过创建一个实现 IEnumerable 接口以及所需状态机的通用类,并将其实例作为静态成员放置在函数内部,应该可以模拟 yield return 函数的效果。

当然,这需要在函数外部实现该类。但如果正确实现,该类应该在一般情况下可重复使用。我还没有深入研究这个想法,无法提供任何实现细节。


嗨,乔尔,你已经至少提到过这个想法两次了。要不要进一步完善你的想法呢? - Andrew Harry
我深入研究了一下,现在我不确定你是否可以在VB.Net的静态局部变量中创建与C#的yield关键字相同类型的状态机。虽然这并非不可能,但肯定不是易事,最终你仍需编写一些奇怪的代码来分配给该机器。即使你想在Visual Studio 2005中实现,也无法做到,因为它需要lambda表达式。 - Joel Coehoorn

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

-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;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接