C#有一个名为yield的关键字。 VB.NET缺少这个关键字。 Visual Basic程序员如何解决缺少此关键字的问题?他们是否实现了自己的迭代器类?或者他们是否尝试编码以避免使用迭代器?
yield关键字会强制编译器在后台进行一些编码。 The implementation of iterators in C# and its consequences (part 1) 就是一个很好的例子。
答案 0 :(得分:71)
C#在编译时将yield关键字转换为状态机。 VB.NET没有yield关键字,但它确实有自己的机制,可以在C#中不容易获得的函数中安全地嵌入状态。
C#static
关键字通常使用Shared
关键字转换为Visual Basic,但有两个地方让事情变得混乱。一个是C#静态类实际上是Visual Basic中的模块而不是共享类(您认为它们允许您在Visual Basic中以任何方式编写它,但是noooo)。另一个是VB.NET确实有自己的Static
关键字。但是,Static
在VB.NET中有不同的含义。
您在VB.NET中使用Static
关键字在函数内声明变量,当您执行变量时,它会在函数调用中保留其状态。这与在C#中声明私有静态类成员不同,因为VB.NET中的静态函数成员也保证是线程安全的,因为编译器将其转换为在编译时使用Monitor类。
那么为什么要在这里写下这一切呢?好吧,应该可以在VB.NET中构建一个可重用的泛型Iterator<T>
类(或Iterator(Of T)
)。在这个类中,您将实现C#使用的状态机,其中Yield()
和Break()
方法对应于C#关键字。然后你可以在一个函数中使用一个静态实例(在VB.NET意义上),这样它最终可以在大约相同数量的代码中完成与C#yield
几乎相同的工作(丢弃类实现本身,因为它可以无限重复使用。)
我对Yield的关注不够自己尝试,但它应该可行。也就是说,它也远非微不足道,因为C#团队成员Eric Lippert称之为“the most complicated transformation in the compiler”。
自从我在一年前写完第一稿以来,我已经开始相信,在Visual Studio 2010问世之前,它不可能以一种有意义的方式实现,因为它需要向Iterator类发送多个lambda,所以要真正实用,我们需要.NET 4对多行lambda的支持。
答案 1 :(得分:21)
Async CTP包括对VB.NET中Yield
的支持。
有关使用情况的信息,请参阅Iterators in Visual Basic。
现在它已包含在Visual Studio 2012的包装盒中了!
答案 2 :(得分:14)
在Visual Studio Magazine中,Bill McCarthy在VB.NET中模拟yield
时有一篇很好的文章 Use Iterators in VB Now 。或者等待下一版本的Visual Basic。
答案 3 :(得分:3)
幸运的是,现在我们已经Yield
返回了
这是我的项目+使用System.Collections.Generic.IEnumerable(T)
函数实现接口的示例:
Public Class Status
Implements IStatus
Private _statusChangeDate As DateTime
Public Property statusChangeDate As DateTime Implements IStatus.statusChangeDate
Get
Return _statusChangeDate
End Get
Set(value As Date)
_statusChangeDate = value
End Set
End Property
Private _statusId As Integer
Public Property statusId As Integer Implements IStatus.statusId
Get
Return _statusId
End Get
Set(value As Integer)
_statusId = value
End Set
End Property
Private _statusName As String
Public Property statusName As String Implements IStatus.statusName
Get
Return _statusName
End Get
Set(value As String)
_statusName = value
End Set
End Property
Public Iterator Function GetEnumerator() As IEnumerable(Of Object) Implements IStatus.GetEnumerator
Yield Convert.ToDateTime(statusChangeDate)
Yield Convert.ToInt32(statusId)
Yield statusName.ToString()
End Function
End Class
Public Interface IStatus
Property statusChangeDate As DateTime
Property statusId As Integer
Property statusName As String
Function GetEnumerator() As System.Collections.Generic.IEnumerable(Of Object)
End Interface
这就是我如何从外部提取所有属性:
For Each itm As SLA.IStatus In outputlist
For Each it As Object In itm.GetEnumerator()
Debug.Write(it & " ")
Next
Debug.WriteLine("")
Next
答案 4 :(得分:1)
我个人只是编写自己的迭代器类,它继承自IEnumerator(Of T)。它确实需要一段时间才能做到正确,但我认为最终写它是正确的,然后尽量避免它。我做的另一个方法是编写一个返回IEnumerable(Of T)的递归方法,只返回List(Of T)并使用.AddRange。
答案 5 :(得分:0)
希望这对即将推出的VB版本来说已成为过去。由于迭代器实际上对于新范例(特别是LINQ与惰性评估相结合)非常重要,因此就保守维克的博客而言,这具有相当高的优先级。再说一次,Paul不再是VB团队的负责人,我还没来得及观看PCD会谈。
尽管如此,如果您感兴趣,它们会在Paul's blog中链接。
答案 6 :(得分:0)
以下代码给出了输出
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;
int result=1;
while (counter < 5)
{
result = result * 2;
counter += 1;
yield return result;
}
}
答案 7 :(得分:0)
VB.NET具有Iterator
关键字https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/modifiers/iterator
自Visual Studio 2012以来似乎