如何在没有关键字的VB.NET中实现迭代器模式?yield
6 回答
现在 VS 2010 SP1 支持 Async CTP,请参阅MSDN 上的 Iterators (C# and Visual Basic)并下载 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 关键字。但是,您可能需要查看知识库文章如何使 Visual Basic .NET 或 Visual Basic 2005 类在 For Each 语句中可用以获取更多信息。
嗯,看起来你可能不走运:
我今天在将一些 C# 转换为 VB.NET 时遇到了一个问题。C# 有一个非常酷的“yield return”语句,它在迭代器块中用于为枚举器对象提供值。VB.NET 没有“yield”关键字。因此,有一些解决方案(没有一个是真正干净的)来解决这个问题。如果您正在循环并希望打破枚举器并返回单个值,则可以使用 return 语句来返回值。但是,如果您想返回整个枚举,请创建子类型的 List() 并返回列表。由于您通常将它与 IEnumerable 一起使用,因此 List() 会很好用。
那是一年前写的,不知道从那以后是否有人想出了更好的东西。
编辑:这将在 VB.NET 版本 11(VS2010 之后的版本)中实现,计划支持迭代器。该规范可在此处获得。
C# 的 yield 关键字强制编译器在后台创建状态机来支持它。VB.Net 没有 yield 关键字。但它确实有一个结构可以让您在函数中创建状态机: 静态函数成员。
应该可以通过创建一个实现 IEnumerable 的通用类以及所需的状态机并将一个实例作为静态成员放置在您的函数中来模拟 yield return 函数的效果。
当然,这需要在函数之外实现类。但是如果做得好,这个类在一般情况下应该是可重用的。不过,我还没有充分考虑这个想法来提供任何实现细节。
请记住,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;
}
}