【发布时间】:2010-09-20 00:51:05
【问题描述】:
VB.NET中没有yield关键字的迭代器模式如何实现?
【问题讨论】:
标签: vb.net design-patterns iterator yield
VB.NET中没有yield关键字的迭代器模式如何实现?
【问题讨论】:
标签: vb.net design-patterns iterator yield
现在 VS 2010 SP1 支持 Async CTP,请参阅:Iterators (C# and Visual Basic) on MSDN 和 download Visual Studio Async CTP (Version 3)。
这样的代码,可以工作:
Private Iterator Function SomeNumbers() As IEnumerable
' Use multiple yield statements.
Yield 3
Yield 5
Yield 8
End Function
【讨论】:
VB.NET 不支持创建自定义迭代器,因此没有等效于 C# 的 yield 关键字。不过,您可能需要查看知识库文章 How to make a Visual Basic .NET or Visual Basic 2005 class usable in a For Each statement 以了解更多信息。
【讨论】:
C# 的 yield 关键字强制编译器在后台创建一个状态机来支持它。 VB.Net 没有 yield 关键字。但它确实有一个结构可以让您在函数中创建状态机:Static function members。
应该可以通过创建一个实现 IEnumerable 的通用类以及所需的状态机并将一个实例作为静态成员放置在函数中来模拟收益返回函数的效果。
当然,这需要在函数之外实现类。但如果做得好,该类在一般情况下应该是可重用的。不过,我还没有充分利用这个想法来提供任何实现细节。
【讨论】:
嗯,看来你可能是out of luck:
我今天在将一些 C# 转换为 VB.NET 时遇到了一个问题。 C# 有一个非常酷的“yield return”语句,它在迭代器块中用于为枚举器对象提供值。 VB.NET 没有“yield”关键字。因此,有一些解决方案(没有一个是真正干净的)来解决这个问题。如果您正在循环并希望打破枚举器并返回单个值,则可以使用 return 语句来返回值。但是,如果您想返回整个枚举,请创建子类型的 List() 并返回列表。由于您通常将它与 IEnumerable 一起使用,因此 List() 会很好用。
那是一年前写的,不知道从那以后是否有人想出了更好的东西..
编辑:这将在 VB.NET 版本 11(VS2010 之后的版本)中实现,计划支持迭代器。规范is available here。
【讨论】:
请记住,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
【讨论】:
下面给出输出: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;
}
}
【讨论】: