我正在尝试解决有关列表类型的问题。首先,我在我的数据库中有一个存储过程,它选择一个列,我尝试在我的应用程序中继续它。通过创建一个方法函数,我声明了一个通过SqlCommand加载的DataTable(具有CloseConnection行为)。之后,我公开声明了一个List(Of String),需要使用正在路上的存储过程中的rows / items进行填充。以下是我的代码片段:
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 Each循环的情况下将那些DataTable中的项插入List(Of String)。
在Visual Studio 2010 Ultimate,.NET Framework 4.0上运行。
答案 0 :(得分:3)
您根本不需要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
可能已遍历整个DataTable,并将每个DataRow引用复制到DataRows列表中;所以,使用这一行,你已经你想要避免的性能损失。
因此,不要自动假设某些For
循环总是慢于某些单个语句。 Measure it,然后优化。
答案 1 :(得分:1)
假设您的DataRow
只有一列,您只需要指示ConvertAll
投射它:
LPrefix = collection.ConvertAll(Function(x) x[0].ToString)
感谢 Binary Worrier 进行c#-2-vb翻译!