在没有 yield
关键字的情况下,如何在 VB.NET 中实现迭代器模式?
现在在VS 2010 SP1中支持此功能,使用Async CTP,详情请参见:MSDN上的迭代器(C#和Visual Basic) 和 下载Visual Studio Async CTP(版本3)。
像这样的代码可以正常工作:
Private Iterator Function SomeNumbers() As IEnumerable
' Use multiple yield statements.
Yield 3
Yield 5
Yield 8
End Function
VB.NET不支持创建自定义迭代器,因此没有与C# yield关键字等效的功能。但是,您可能需要查看KB文章“如何使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 函数的效果。
当然,这需要在函数外部实现该类。但如果正确实现,该类应该在一般情况下可重复使用。我还没有深入研究这个想法,无法提供任何实现细节。
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
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;
}
}