【问题标题】:Resharper, linq within foreach loopResharper,foreach循环中的linq
【发布时间】:2014-11-26 20:25:31
【问题描述】:

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

【问题讨论】:

  • 您的意思是_executeFunc内可能发生异常?
  • 了解延迟执行。
  • 抱歉,是的,executeFunc(row) 容易抛出错误

标签: c# linq foreach resharper


【解决方案1】:

在这种情况下,这些语句在语义上与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】:

    在您的第一个示例中,在您的 foreach 循环开始之前,不会首先为 rows 中的每个项目调用 _executeFunc(row)。 LINQ 将延迟执行。详情请见This answer

    事件的顺序是:

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

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

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

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

    【讨论】:

    • 谢谢你们两个很好的答案,希望我能选择两个作为正确答案。我选择了 J. Steen's,因为它提供了一个输出示例,抱歉
    • 没问题,很高兴你找到了答案!
    【解决方案3】:

    在上面的示例中,使用Select 将通过yielding 逐一投影行。

    所以

    foreach (var result in rows.Select(row =&gt; _executeFunc(row)))

    基本一样

    foreach(var row in rows)

    因此 Select 正在做这样的事情

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

    yield 将每一行一个接一个地传回(比这复杂一点,但现在这个解释应该足够了)。

    如果你这样做

    foreach (var result in rows.Select(row =&gt; _executeFunc(row)).ToList())

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

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

    【讨论】:

      【解决方案4】:

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

      • rows取件
      • 拨打_executeFunc就可以了
      • 根据_executeFunc 的结果调用RunStoredProcedure

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-06-12
          • 1970-01-01
          • 2011-04-26
          • 2011-03-12
          • 1970-01-01
          • 2013-07-08
          相关资源
          最近更新 更多