【问题标题】:Iterator pattern in VB.NET (C# would use yield!) [duplicate]VB.NET 中的迭代器模式(C# 将使用 yield!)[重复]
【发布时间】:2010-09-20 00:51:05
【问题描述】:

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

【问题讨论】:

    标签: vb.net design-patterns iterator yield


    【解决方案1】:

    现在 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
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

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

        应该可以通过创建一个实现 IEnumerable 的通用类以及所需的状态机并将一个实例作为静态成员放置在函数中来模拟收益返回函数的效果。

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

        【讨论】:

        • 嘿乔尔,你已经至少两次提到这个想法了。想进一步充实您的想法吗?
        • 我对此进行了更深入的研究,但我不再确定您是否可以在 VB.Net 静态局部变量中创建与 C# 的 yield 关键字相同类型的状态机。并不是说这是不可能的,但它肯定不会是微不足道的,最后你仍然必须编写一些分配给机器的奇怪代码。即使您在 Visual Studio 2005 中也做不到,因为它需要 lambda 表达式。
        【解决方案4】:

        嗯,看来你可能是out of luck

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

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


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

        【讨论】:

          【解决方案5】:

          请记住,LINQ 表达式和方法的延迟执行和惰性求值属性允许我们有效地实现自定义迭代器,直到 yield 语句在 .NET 4.5 中可用。 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
          

          【讨论】:

            【解决方案6】:

            下面给出输出: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;
                }
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-01-07
              • 1970-01-01
              • 2010-11-08
              • 2021-10-16
              • 2015-03-11
              • 2020-05-18
              • 2012-03-23
              • 1970-01-01
              相关资源
              最近更新 更多