【问题标题】:looping through data table to get two specifics values from each row循环遍历数据表以从每一行获取两个具体值
【发布时间】:2020-12-17 00:51:40
【问题描述】:

我正在尝试遍历 datatable 并打印出的值

  • 0,
  • 1 和
  • 每行的第 4 个单元格,

感觉这应该可以工作,但我可能以某种方式搞砸了循环。

 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() + " ");
       }
 }

上面的代码给了我这个错误:

系统无法执行指定的程序。

【问题讨论】:

  • 对于初学者来说,您只需要 foreachfor 循环。你不需要两者。
  • 如果你只想要值,你可能可以去foreach (var dr in dt.Rows) Console.WriteLine($"{dr[0]} - {dr[1]} - {dr[4]}");

标签: c# oracle datatable


【解决方案1】:

我只是想指出,您确实可以通过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
}

【讨论】:

    【解决方案2】:

    您不需要在行上用foreach 循环包围您的for 循环。 (你根本没有使用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] + " ");
        }
    }
    

    【讨论】:

    • 现在,如果我想将项目数组的值存储在字符串 ex 中,而不是写行:string toEmail = dt.Rows[idx].ItemArray[4].ToString(); console.writeline(toEmail); 再次抛出我遇到的相同错误。因为我要结束的游戏是循环使用这 3 个值来填充多个字符串,这些字符串将成为电子邮件的收件人/发件人/正文
    • @chessmt 为了能够帮助您解决错误,我需要查看修改后的代码和异常的整个堆栈跟踪。请不要修改原始问题的代码,而是打开一个新问题并在此处链接。
    • 我很确定你可以通过他们的名字访问DataRow.Items
    【解决方案3】:

    删除其中一个循环:

                    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]}");
                    }
    

    【讨论】:

    • 谢谢!不知道为什么我认为我需要两个循环来获取所有值
    猜你喜欢
    • 2019-08-13
    • 1970-01-01
    • 2016-01-10
    • 1970-01-01
    • 2022-08-18
    • 2017-06-12
    • 2014-06-29
    • 2011-03-09
    • 2013-06-11
    相关资源
    最近更新 更多