我正在尝试遍历datatable
并打印出
感觉这应该可行,但是我可能以某种方式弄乱了循环。
foreach (DataRow dr in dt.Rows)
{
for (int x = 0; x < dt.Rows.Count; x++)
{
Console.WriteLine(dt.Columns[0].ColumnName + " ");
Console.WriteLine(dt.Rows[x].ItemArray[0].ToString() + " ");
Console.WriteLine(dt.Columns[1].ColumnName + " ");
Console.WriteLine(dt.Rows[x].ItemArray[1].ToString() + " ");
Console.WriteLine(dt.Columns[4].ColumnName + " ");
Console.WriteLine(dt.Rows[x].ItemArray[4].ToString() + " ");
}
}
上面的代码给我这个错误:
系统无法执行指定的程序。
答案 0 :(得分:2)
删除其中一个循环:
for (int x = 0; x < dt.Rows.Count; x++)
{
Console.WriteLine(dt.Columns[0].ColumnName + " ");
Console.WriteLine(dt.Rows[x].ItemArray[0].ToString() + " ");
Console.WriteLine(dt.Columns[1].ColumnName + " ");
Console.WriteLine(dt.Rows[x].ItemArray[1].ToString() + " ");
Console.WriteLine(dt.Columns[4].ColumnName + " ");
Console.WriteLine(dt.Rows[x].ItemArray[4].ToString() + " ");
}
或
foreach (DataRow dr in dt.Rows){
Console.WriteLine($"{dr[0]} - {dr[1]} - {dr[4]}");
}
答案 1 :(得分:1)
您无需在行上用for
循环包围foreach
循环。 (您根本没有使用dr
)
for (int idx = 0; idx < dt.Rows.Count; idx++)
{
Console.WriteLine(dt.Columns[0].ColumnName + " ");
Console.WriteLine(dt.Rows[idx].ItemArray[0] + " ");
Console.WriteLine(dt.Columns[1].ColumnName + " ");
Console.WriteLine(dt.Rows[idx].ItemArray[1] + " ");
Console.WriteLine(dt.Columns[4].ColumnName + " ");
Console.WriteLine(dt.Rows[idx].ItemArray[4] + " ");
}
更通用的版本:
int[] columnIndexes = new[] { 0, 1, 4 };
for (int rowIndex = 0; rowIndex < dt.Rows.Count; rowIndex++)
{
for (int columnIndex = 0; columnIndex < columnIndexes.Length; columnIndex++)
{
Console.WriteLine(dt.Columns[columnIndex].ColumnName + " ");
Console.WriteLine(dt.Rows[rowIndex].ItemArray[columnIndex] + " ");
}
}
如果您要使用foreach遍历Rows集合,则可以这样做,但要复杂一些。
DataTable的Rows属性是DataRowCollection。它公开了GetEnumerator
循环必不可少的foreach
方法。
foreach (DataRow dr in dt.Rows)
{
//dr does not provide you direct access to the ColumnName
}
您不能直接从DataRow访问ColumnName。所有需要做的就是为列名创建一个“查找表”,其中键是索引,值是列名。
int colIdx = 0;
var columnNames = dt.Columns
.Cast<DataColumn>()
.ToDictionary(_ => colIdx++, column => column.ColumnName);
之后,您的foreach循环将如下所示:
int[] columnIndexes = new[] {0, 1, 4};
foreach (DataRow row in dt.Rows)
{
for (int columnIndex = 0; columnIndex < columnIndexes.Length; columnIndex++)
{
Console.WriteLine(columnNames[columnIndex] + " ");
Console.WriteLine(row.ItemArray[columnIndex] + " ");
}
}
答案 2 :(得分:0)
我只是想指出,您确实可以通过column name访问DataRow
中的值。该功能在完整的.net框架和.net核心中都可用(因此,无论使用哪种版本,您都可以使用)。
当然这会对性能造成轻微影响,因为它似乎最终会进行Dictionary
查找。
采用这种方法所获得的一个好处是,将来您对表结构的更改将不再那么依赖-这可能是一个值得考虑的折衷方案。
那么您的意图可以这样表达:
foreach (DataRow row in dt.Rows)
Console.WriteLine($"{row["Col0"]} - {row["Col1"]} - {row["Col4"]}");
现在,假设您想放下foreach
并前进LINQ
:
void Main()
{
var dt = new DataTable();
dt.Columns.Add("Col0", typeof(string));
dt.Columns.Add("Col1", typeof(string));
dt.Columns.Add("Col2", typeof(string));
dt.Columns.Add("Col3", typeof(string));
dt.Columns.Add("Col4", typeof(string));
dt.Rows.Add("one","two","three","four","five");
dt.Rows.Add("ten","eleven","twelve","thirteen","fourteen");
var formattedItems = dt.Rows // declaring a lise you'd open yourself up to further processing the results rather than just pringint them
.Cast<DataRow>() // DataRow collection does implement IEnumerable through its base InternalDataCollectionBase class but we seem to need this cast in order to properly expose it
.Select(row => $"{row["Col0"]} - {row["Col1"]} - {row["Col4"]}") // and now we can unleash the LINQ
.ToList(); // depending on your further processing code you can either enumerate it now or have it sitting around until you actually need to loop through it
Console.WriteLine(formattedItems.Aggregate(new StringBuilder(), (sb, s) => sb.AppendLine(s)).ToString()); // just slapping list items together in a string to print out for your convenience
}