我有一些实现此接口的对象:
public interface IRow
{
void Fill(DataRow dr);
}
通常当我从db中选择一些东西时,我会去:
public IEnumerable<IRow> SelectSomeRows
{
DataTable table = GetTableFromDatabase();
foreach (DataRow dr in table.Rows)
{
IRow row = new MySQLRow(); // Disregard the MySQLRow type, it's not important
row.Fill(dr);
yield return row;
}
}
现在使用.Net 4,我想使用AsParallel,因此使用LINQ。
我已经对它进行了一些测试,并且它加速了很多东西(IRow.Fill使用Reflection,所以在CPU上很难)
无论如何我的问题是,我如何创建一个LINQ查询,它将Fills称为查询的一部分,所以它被正确并行化了?
为了测试性能,我创建了一个构造函数,它将DataRow作为参数,但是我真的喜欢以某种方式避免这种情况。
有了构造函数,它显然很简单:
public IEnumerable<IRow> SelectSomeRowsParallel
{
DataTable table = GetTableFromDatabase();
return from DataRow dr in table.Rows.AsParallel()
select new MySQLRow(dr);
}
但是就像我说的那样,我真的很想能够将我的Fill方法填充到LINQ查询中,因此不需要构造函数重载。
答案 0 :(得分:4)
你需要创建一个多语句lambda表达式,如下所示:
table.AsEnumerable().AsParallel().Select(dr =>
IRow row = new MySQLRow();
row.Fill(dr);
return row;
});
答案 1 :(得分:1)
答案很幸运很简单。就这样做:)没有什么可以阻止你在查询的选择部分中调用一个方法
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;)
}
我不确定你是否可以在那里填充lambda(自从我有机会编写LINQ几年后)如果你不能将它分配给Func
Func<IRow,DataRow> getRow =
(row =>
var mysqlRow = new MySQLRow()
mysqlRow.Fill(row);
return mysqlRow;)
然后在你的select子句中调用它
答案 2 :(得分:1)
我认为没有办法将命令式操作(例如调用返回Fill
的{{1}}方法)放入LINQ查询语法中,但是你可以这样做使用显式调用void
方法的东西,它允许你使用任意代码:
Select
您需要将调用添加到DataTable table = GetTableFromDatabase();
return table.Rows.Cast<DataRow>().AsParallel().Select(dr => {
IRow row = new MySQLRow();
row.Fill(dr);
return dr; });
(因为DataSet不实现Cast
的通用版本),其余代码非常简单。您的原始查询将完全转换为这些调用。
如果你想做一些技巧,你可以修改界面,以便IEnumerable
方法返回一些东西(例如Fill
)。然后,您可以使用int
子句并忽略返回的值。
let
可以使用这种返回内容的技巧调用方法,但不能使用返回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;
的方法。