在LINQ查询中的对象构造之后立即调用方法

时间:2010-05-02 18:47:09

标签: c# linq-to-objects

我有一些实现此接口的对象:

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查询中,因此不需要构造函数重载。

3 个答案:

答案 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; 的方法。