Parallel ForEach on DataTable

C# 4.0Parallel Processing

C# 4.0 Problem Overview


I would like to use the new Parallel.ForEach function to loop through a datatable and perform actions on each row. I am trying to convert the code below:

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

To this code:

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

When I run the new code I get the error:

The type arguments for method 'System.Threading.Tasks.Parallel.ForEach(System.Collections.Generic.IEnumerable, System.Action)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

What is the correct syntax for this?

C# 4.0 Solutions


Solution 1 - C# 4.0

DataTable.Rows returns a DataRowCollection which only implements IEnumerable, not IEnumerable<DataRow>. Use the AsEnumerable() extension method on DataTable (from DataTableExtensions) instead:

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

Solution 2 - C# 4.0

This is better than the accepted answer because this does not need to reference System.Data.DataSetExtensions:

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

To use ForEach with a non-generic collection, you can use the Cast extension method to convert the collection to a generic collection, as shown in this example.

Solution 3 - C# 4.0

Parallel.ForEach() expects the first argument to be an IEnumerable<> type. DataTable.Rows is not, but you can turn it into one with the AsEnumerable() extension method. Try:

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

Solution 4 - C# 4.0

This way we can use Parallel.ForEach for Data table.

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

Solution 5 - C# 4.0

I had to modify Jon Skeet's answer to make it work.

Parallel.ForEach(dt.AsEnumerable<DataRowType>(), drow => {
     drow.SomeCol = "";
});

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSchwartzEView Question on Stackoverflow
Solution 1 - C# 4.0Jon SkeetView Answer on Stackoverflow
Solution 2 - C# 4.0Kevin .NETView Answer on Stackoverflow
Solution 3 - C# 4.0JaredReisingerView Answer on Stackoverflow
Solution 4 - C# 4.0Indi_RainView Answer on Stackoverflow
Solution 5 - C# 4.0irfandarView Answer on Stackoverflow