我正在尝试解决有关列表类型的问题。首先,我的数据库中有一个存储过程,它选择单个列,我尝试在 VB 中的应用程序中继续它。通过创建一个方法函数,我声明了一个通过 SqlCommand 加载的 DataTable(具有 CloseConnection 行为(。之后,我公开声明了一个 List(Of String(,它需要使用正在进行的存储过程中的行/项进行填充。下面是我的代码片段:
Dim dt As New DataTable()
Try
If conn.State = ConnectionState.Open Then
conn.Close()
Else
conn.Open()
Dim cmd = New SqlCommand("LoadCodes", conn)
cmd.CommandType = CommandType.StoredProcedure
dt.Load(cmd.ExecuteReader(CommandBehavior.CloseConnection))
Dim collection As New List(Of DataRow)
collection = dt.AsEnumerable.ToList
LPrefix = collection.Cast(Of String)()
End If
Catch ex As Exception
MsgBox(ex.Message + vbCritical)
End Try
LPrefix = collection.Cast(Of String)()
我收到异常错误的地方,告诉我我无法真正转换它。旧时尚的方式是迭代 for/for 每个循环,但这不是我想要的最佳性能利用,特别是如果列表在一列中有数千行。所以基本上我想将这些项目从该数据表插入到列表(字符串(而不使用 For/For 每个循环。
运行在Visual Studio 2010 Ultimate,.NET Framework 4.0上。
你根本不需要你的collection
。使用 LINQ,可以直接从数据表中提取第一列:
dt.Load(cmd.ExecuteReader(CommandBehavior.CloseConnection))
LPrefix = (From row In dt.AsEnumerable()
Select row.Field(Of String)(0)).ToList()
当然,这可能会在内部使用循环,但由于您希望将每个值复制到字符串列表中,因此如果不循环访问数据行,则无法执行此操作。
另一种选择是使用 IEnumerable(Of String)
而不是 List(Of String)
:
dt.Load(cmd.ExecuteReader(CommandBehavior.CloseConnection))
Dim LPrefixNew As IEnumerable(Of String) = _
From row In dt.AsEnumerable()
Select row.Field(Of String)(0)
您可以像遍历列表一样遍历 IEnumerable,但求值是惰性的:只要您不访问元素,就不会遍历 DataTable。因此,访问此 IEnumerable 就像直接从 DataTable 读取元素一样,只是以更方便的方式。
另一个建议:在你衡量性能之前,你不应该试图推理它。例如,您的行collection = dt.AsEnumerable.ToList
可能已经遍历了整个数据表,并将每个数据行引用复制到数据行列表中;因此,使用此行,您已经有了试图避免的性能损失。
因此,不要自动假设某些For
循环总是比某些单个语句慢。测量它,然后优化。
假设你的DataRow
只有一列,你只需要指示ConvertAll
投射它:
LPrefix = collection.ConvertAll(Function(x) x[0].ToString)
感谢 Binary Worrier 的 c#-2-vb 翻译!