Method call immediately after building the object in LINQ query

I have some objects that implement this interface:

public interface IRow { void Fill(DataRow dr); } 

Usually, when I select something from db, I go:

 public IEnumerable<IRow> SelectSomeRows { DataTable table = GetTableFromDatabase(); foreach (DataRow dr in table.Rows) { IRow row = new MySQLRow(); // Disregard the MySQLRow type, it not important row.Fill(dr); yield return row; } } 

Now with .Net 4, I would like to use AsParallel and therefore LINQ.

I did some testing on it and it speeds up significantly (IRow.Fill uses Reflection, so it is very processor dependent)

In any case, my problem is, how can I create a LINQ query that calls Fills as part of the query, so is it parallelized correctly?

For performance testing, I created a constructor that took a DataRow as an argument, but I would really like to avoid this if possible.

With the constructor in place, it is obviously quite simple:

 public IEnumerable<IRow> SelectSomeRowsParallel { DataTable table = GetTableFromDatabase(); return from DataRow dr in table.Rows.AsParallel() select new MySQLRow(dr); } 

However, as I said, I would really like to just populate my Fill method in the LINQ query and, therefore, do not need to overload the constructor.

+4
source share
3 answers

You need to make a multibyte ambda expression, for example:

 table.AsEnumerable().AsParallel().Select(dr => IRow row = new MySQLRow(); row.Fill(dr); return row; }); 
+4
source

The answer, fortunately, is very simple. Just do it :) There is nothing stopping you from simply calling the method in the selected part of the request

 public IEnumerable<IRow> SelectSomeRowsParallel { DataTable table = GetTableFromDatabase(); return from DataRow dr in table.Rows.AsParallel() select (row => var mysqlRow = new MySQLRow() mysqlRow.Fill(row); return mysqlRow;) } 

I'm not sure if you can fill a lambda there (several years have passed since I had the opportunity to write LINQ) if you cannot assign it Func

 Func<IRow,DataRow> getRow = (row => var mysqlRow = new MySQLRow() mysqlRow.Fill(row); return mysqlRow;) 

and then call this in the select clause

+1
source

I don’t think there is any way to put an imperative operation (for example, calling the Fill method that returns void ) into the LINQ query syntax, but you can do the same using an explicit call to the Select method, which allows you to use arbitrary code:

 DataTable table = GetTableFromDatabase(); return table.Rows.Cast<DataRow>().AsParallel().Select(dr => { IRow row = new MySQLRow(); row.Fill(dr); return dr; }); 

You need to add a Cast call (because DataSets does not implement the general version of IEnumerable ), and the rest of the code is pretty simple. Your original request will translate precisely to these challenges.

If you want to do some tricks, you can change the interface so that the Fill method returns something (like int ). Then you can use the let clause and ignore the return value.

 return from DataRow dr in table.AsParallel() let IRow row = new MySQLRow() let _ = row.Fill(dr) // ignoring return value; '_' is just variable name select row; 

You can use these methods to call tricks that return something, but not methods that return void .

+1
source

Source: https://habr.com/ru/post/1308613/


All Articles