Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 来自Eric Lippert的博客:“不要关闭循环变量”_C#_Linq_Closures - Fatal编程技术网

C# 来自Eric Lippert的博客:“不要关闭循环变量”

C# 来自Eric Lippert的博客:“不要关闭循环变量”,c#,linq,closures,C#,Linq,Closures,可能的重复项: 从输入开始: var s=序列;看起来像是禁区,为什么不是?直接使用序列会出现什么问题 而且,更主观地说:这在多大程度上被认为是C行为中的一个缺点?这是一个微妙的范围问题,与闭包和延迟执行的工作方式有关 如果不使用局部变量,而是直接使用序列,则结果IEnumarable将绑定到变量序列而不是序列的值,并且在执行查询时,变量序列包含序列的最后一个值 如果像Eric的示例中那样声明另一个局部变量,则范围仅限于每个循环迭代。因此,即使推迟执行,也将按照预期进行评估。Eric本人的几篇

可能的重复项:

从输入开始:

var s=序列;看起来像是禁区,为什么不是?直接使用序列会出现什么问题


而且,更主观地说:这在多大程度上被认为是C行为中的一个缺点?

这是一个微妙的范围问题,与闭包和延迟执行的工作方式有关

如果不使用局部变量,而是直接使用序列,则结果IEnumarable将绑定到变量序列而不是序列的值,并且在执行查询时,变量序列包含序列的最后一个值


如果像Eric的示例中那样声明另一个局部变量,则范围仅限于每个循环迭代。因此,即使推迟执行,也将按照预期进行评估。

Eric本人的几篇相关文章,以及评论中的一些有趣的讨论:


该博客帖子上的评论之一:

然而,在您的第一个应用程序中有一个bug CartesianProduct方法的版本 :您正在接近环路 变量,因此,由于延迟 执行,它使笛卡尔 最后一个序列与的乘积 它本身您需要添加一个临时 foreach循环中的局部变量 让它在第二个版本中工作 不过效果不错


这里使用的LINQ查询导致s的值在最初定义的范围(即CartesianProduct方法)之外可用。这就是所谓的a。由于执行延迟,当LINQ查询实际被评估时(假设它最终被评估),封闭方法将完成,s变量将“超出范围”,至少根据传统的范围规则是这样。尽管如此,在这种情况下,引用s

闭包在传统的函数式编程语言中非常方便且表现良好,在这种语言中,事物自然是不可变的。事实上,C语言首先是一种命令式编程语言,默认情况下变量是可变的,这是导致这种奇怪的解决方法的基础


通过在循环范围内创建中间变量,可以有效地指示编译器为LINQ查询的每次迭代分配一个单独的非共享变量。否则,每次迭代都将共享同一个变量实例,这显然也是相同的值…可能不是您想要的。

这已经被问过1000次了,我不知道这一点,很高兴已经有一百万个线程了。
static IEnumerable<IEnumerable<T>>
  CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences)
{
  // base case:
  IEnumerable<IEnumerable<T>> result = new[] { Enumerable.Empty<T>() };

  foreach(var sequence in sequences)
  {
    var s = sequence; // don't close over the loop variable

    // recursive case: use SelectMany to build the new product out of the old one
    result = 
      from seq in result
      from item in s
      select seq.Concat(new[] {item});
  }

  return result;
}