我能否在VB.NET中实现IEnumerable函数的yield return?

9

可能是重复的问题:
在VB.NET中使用Yield

在C#中,当编写返回IEnumerble<>的函数时,可以使用yield return来返回枚举的单个项,而使用yield break;表示没有剩余的项。那么在VB.NET中怎样做呢?

NerdDinner代码中的一个示例:

public IEnumerable<RuleViolation> GetRuleViolations() {

   if (String.IsNullOrEmpty(Title))
       yield return new RuleViolation("Title required","Title");

   if (String.IsNullOrEmpty(Description))
       yield return new RuleViolation("Description required","Description");

   if (String.IsNullOrEmpty(HostedBy))
       yield return new RuleViolation("HostedBy required", "HostedBy");

   if (String.IsNullOrEmpty(Address))
       yield return new RuleViolation("Address required", "Address");

   if (String.IsNullOrEmpty(Country))
       yield return new RuleViolation("Country required", "Country");

   if (String.IsNullOrEmpty(ContactPhone))
       yield return new RuleViolation("Phone# required", "ContactPhone");

   if (!PhoneValidator.IsValidNumber(ContactPhone, Country))
       yield return new RuleViolation("Phone# does not match country", "ContactPhone");

   yield break;
}

这个将C#转换为VB.NET的工具出现了“不支持YieldStatement”错误。

请注意,yielding并不是返回,至少不是大多数人所指的返回(尽管在实现方式方面不可忽略)。此外,在那里你不需要使用yield break。另外,您可能还希望考虑将代码从RuleViolation对象的枚举转换为Func<MyModelClass,RuleViolation>委托的枚举。 - yfeldblum
使用yield让我想起管道,因为调用代码可以在返回ienumerable的函数完成运行之前开始迭代。非常酷! - Neil Trodden
2
这是一个糟糕的例子,因为像这样的东西明显不需要使用yield:懒惰地确定规则违规的好处是什么?把它们全部放在列表中就可以了。这并不是说yield没有用,但这只是一个糟糕的例子。 - piers7
@piers7,自从我发布这个问题以来,我对yield和迭代器有了更深入的了解,我必须同意你的观点。这只是我第一次看到yield的地方,所以我才包含了那个例子。到目前为止,我见过的最好的例子是一个质数生成器,它没有预设的大小限制(当然除了MaxInt)。 - CoderDennis
哇,使用VB仅5分钟,我就遇到了一个重大问题。我想知道还有什么其他的问题。虽然我不是每天都使用yield return,但我确实每天都使用它使我能够编写的函数。我要告诉管理层,我在这个项目中不会使用VB :-) 我以为VB已经赶上了C#。 - MikeKulls
1
对于piers7,我不确定这是一个坏的例子。它按照要求评估条件,并在任何消耗它的东西停止时停止。 - MikeKulls
6个回答

13

8

2

请查看我的答案:

总结一下:
VB.Net没有yield,但是C#通过将您的代码转换为状态机来实现yield。 VB.Net的Static关键字还允许您在函数内部存储状态,因此理论上应该能够实现一个类,使其在作为方法的Static成员使用时可以编写类似的代码。


0
以下是输出结果:2、4、8、16、32
在VB中,
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

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

2
对于这个简单的示例,那应该可以。还有其他更好的迭代器示例,您不想或不能在单个函数调用内创建整个列表。您的 C# 代码仅在 foreach 循环中使用它们时计算每个值。VB 代码在调用 setOfNumbers 函数时计算所有值。 这是一个显着的区别。 - CoderDennis

0

VB.NET 中没有 yield return :( 只需创建一个列表并返回它。


0

在幕后,编译器创建了一个枚举器类来完成工作。由于 VB.NET 没有实现此模式,您必须创建自己的 IEnumerator(Of T) 实现。


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