【问题标题】:Parallel ForEach on DataTableDataTable 上的并行 ForEach
【发布时间】:2010-08-04 18:25:11
【问题描述】:

我想使用新的 Parallel.ForEach 函数循环遍历数据表并对每一行执行操作。我正在尝试转换以下代码:

        foreach(DataRow drow in dt.Rows)
        {
           ...
           Do Stuff
           ...
        }

到此代码:

        System.Threading.Tasks.Parallel.ForEach(dt.Rows, drow =>
                {
                    ...
                    Do Stuff
                    ...
                });

当我运行新代码时出现错误:

无法从用法中推断方法“System.Threading.Tasks.Parallel.ForEach(System.Collections.Generic.IEnumerable, System.Action)”的类型参数。尝试明确指定类型参数。

正确的语法是什么?

【问题讨论】:

    标签: c#-4.0 parallel-processing


    【解决方案1】:

    DataTable.Rows 返回一个DataRowCollection,它只实现IEnumerable,而不是IEnumerable<DataRow>。在DataTable(来自DataTableExtensions)上使用AsEnumerable() 扩展方法:

    Parallel.ForEach(dt.AsEnumerable(), drow =>
    {
        ...
        Do Stuff
        ...
    });
    

    【讨论】:

    • 天啊!击败拳头(仅几秒钟)!
    • 这个相同的扩展是否可用于实现 IEnumerable 的其他集合?比如 TreeNodeCollection?还是我必须自己创建这个扩展?
    • @Scott:你必须自己写——否则它不会知道返回哪种类型的IEnumerable<T>,如果你明白我的意思的话。
    • 确保引用 System.Data.DataSetExtensions
    • 请注意,DataTable 不是线程安全的。您可能会遇到“内部索引已损坏”错误。 stackoverflow.com/questions/450675/…
    【解决方案2】:

    这比接受的答案要好,因为它不需要引用 System.Data.DataSetExtensions:

     Parallel.ForEach(dt.Rows.Cast<DataRow>(), dr =>
    

    要将 ForEach 与非泛型集合一起使用,您可以使用 Cast 扩展方法将集合转换为泛型集合,如本示例所示。

    【讨论】:

    • 但是请记住这一点,来自Cast docs:“如果一个元素不能转换为TResult类型,这个方法会抛出异常。要只获取那些可以转换为TResult类型的元素,使用 OfType 方法而不是 Cast(IEnumerable)。"
    【解决方案3】:

    Parallel.ForEach() 期望第一个参数是 IEnumerable 类型。 DataTable.Rows 不是,但您可以使用 AsEnumerable() 扩展方法将其合二为一。试试:

    ... Parallel.ForEach(dt.AsEnumerable(), drow => ...
    

    【讨论】:

      【解决方案4】:

      这样我们就可以将 Parallel.ForEach 用于数据表。

      DataTable dtTest = new DataTable();
                  dtTest.Columns.Add("ID",typeof(int));
                  dtTest.Columns.Add("Name", typeof(string));
                  dtTest.Columns.Add("Salary", typeof(int));
      
                  DataRow dr = dtTest.NewRow();
                  dr["ID"] = 1;
                  dr["Name"] = "Rom";
                  dr["Salary"] = "2000";
                  dtTest.Rows.Add(dr);
      
                  dr = dtTest.NewRow();
                  dr["ID"] = 2;
                  dr["Name"] = "David";
                  dr["Salary"] = "5000";
                  dtTest.Rows.Add(dr);
      
                  dr = dtTest.NewRow();
                  dr["ID"] = 3;
                  dr["Name"] = "Samy";
                  dr["Salary"] = "1200";
                  dtTest.Rows.Add(dr);
      
                  Parallel.ForEach(dtTest.AsEnumerable(), drow =>
                  {
                      MessageBox.Show("ID " + drow.Field<int>("ID") + " " + drow.Field<string>("Name") + " " + drow.Field<int>("Salary"));
                  });
      

      【讨论】:

        【解决方案5】:

        我不得不修改 Jon Skeet 的答案以使其正常工作。

        Parallel.ForEach(dt.AsEnumerable<DataRowType>(), drow => {
             drow.SomeCol = "";
        });
        
        猜你喜欢
        • 2018-11-30
        • 2018-03-03
        • 1970-01-01
        • 2020-06-17
        • 2017-12-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多