Resharper,linq在foreach循环中

时间:2014-11-20 14:34:11

标签: c# linq foreach resharper

Resharper建议在最底层的例子中使用顶部示例。但是我的印象是首先会创建一个新的项目列表,因此所有_executeFuncs都将在调用runstoredprocedure之前运行。

这通常不是问题,但是容易发生异常,如果我的假设是正确的,那么尽管已经运行了函数,我的数据库也不会更新?

foreach (var result in rows.Select(row => _executeFunc(row)))
   {                   
      RunStoredProcedure(result)
   }

或者

 foreach(var row in rows)
   {
       var result = _executeFunc(row);
       RunStoredProcedure(result);
   }

5 个答案:

答案 0 :(得分:4)

在您的第一个示例中,在_executeFunc(row)循环开始之前,rows中的每个项目都不会首先调用foreach。 LINQ将推迟执行。有关详细信息,请参阅This answer

活动顺序如下:

  1. 评估rows
  2. 中的第一项
  3. 在该项目上致电executeFunc(row)
  4. 致电RunStoredProcedure(result)
  5. 重复rows
  6. 中的下一项

    现在,如果您的代码是这样的:

    foreach (var result in rows.Select(row => _executeFunc(row)).ToList())
    {                   
       RunStoredProcedure(result)
    }
    

    然后它将首先为.Select中的每个项运行LINQ rows,因为.ToList()会导致集合被枚举。

答案 1 :(得分:4)

在这种情况下,语句在语义上与Select(和一般的linq)相同,使用委托的延迟执行。在结果生效之前,它不会运行任何已声明的查询,并且根据您编写该查询的方式,它将以适当的顺序执行。

一个非常简单的例子来说明:

var list = new List<string>{"hello", "world", "example"};

Func<string, string> func = (s) => {
    Console.WriteLine(s);
    return s.ToUpper();
};

foreach(var item in list.Select(i => func(i)))
{
    Console.WriteLine(item);
}

结果

hello
HELLO
world
WORLD
example
EXAMPLE

答案 2 :(得分:3)

在上面的示例中,使用Select将按行yielding逐个投影行。

所以

foreach (var result in rows.Select(row => _executeFunc(row)))

基本相同

foreach(var row in rows)

因此Select正在做这样的事情

for each row in source
   result = _executeFunc(row)
   yield result

这个收益率是逐一传递每一行(它比这复杂一点,但这个解释现在应该足够了)。

如果你这样做了

foreach (var result in rows.Select(row => _executeFunc(row)).ToList())

调用ToList()将立即返回行列表,这意味着在您有机会调用RunStoredProcedure()之前,确实会为每一行调用_executeFunc()。

因此,Resharper所建议的是有效的。公平地说,我确信Jetbrains开发者知道他们在做什么:)

答案 3 :(得分:2)

Select使用延迟执行。这意味着它将按顺序:

  • rows
  • 中选择一项
  • 打电话给_executeFunc
  • RunStoredProcedure
  • 的结果致电_executeFunc

然后它将对下一个项目执行相同操作,直到所有列表都已处理完毕。

答案 4 :(得分:1)

执行将被推迟意味着他们将具有相同的exec