C# “访问修改的闭包”是否通过理解语法解决?

C# “访问修改的闭包”是否通过理解语法解决?,c#,warnings,resharper-6.0,list-comprehension,C#,Warnings,Resharper 6.0,List Comprehension,ReSharper 6.0允许我访问第一个代码段中dr标识符的修改关闭警告 私有IEnumerable GetTheDataTableString数据表dt{ foreach数据行dr在dt.行中{ 收益返回GetStringFuncOutput=>dr.ToString; } } 我想我已经基本了解了这个警告试图保护我不受的影响:在获取DataTableString的输出之前,dr更改了几次,因此调用方可能无法获得我期望的输出/行为 但是R没有对第二个代码段给出任何警告 私有IEnumerab

ReSharper 6.0允许我访问第一个代码段中dr标识符的修改关闭警告

私有IEnumerable GetTheDataTableString数据表dt{ foreach数据行dr在dt.行中{ 收益返回GetStringFuncOutput=>dr.ToString; } } 我想我已经基本了解了这个警告试图保护我不受的影响:在获取DataTableString的输出之前,dr更改了几次,因此调用方可能无法获得我期望的输出/行为

但是R没有对第二个代码段给出任何警告

私有IEnumerable GetTheDataTableString数据表dt{ 从dt.Rows中的DataRow dr返回选择GetStringFuncOutputdr.ToString; } 在使用理解语法时,我是否可以放弃此警告/问题

其他代码:

字符串GetStringFuncOutputFunc stringFunc{ 返回stringFunc; }
首先,关注第一个版本是正确的。由该lambda创建的每个委托都在同一个变量上关闭,因此随着该变量的更改,查询的含义也会更改

第二,仅供参考,我们很有可能在下一版本的C中解决这个问题;这是开发人员的一个主要痛点

更新:这个答案写于2011年。事实上,我们确实采取了C 5中描述的修复方法

在下一个版本中,每次运行foreach循环时,我们都会生成一个新的循环变量,而不是每次都关闭同一个变量。这是一个突破性的变化,但在绝大多数情况下,突破将被修复,而不是导致错误

for循环将不会更改

有关详细信息,请参阅

第三,查询理解版本没有问题,因为没有正在修改的封闭变量。查询理解表与您所说的相同:

return dt.Rows.Select(dr=>GetStringFuncOutput(dr.ToString));

lambda没有在任何外部变量上关闭,因此没有要意外修改的变量。

Resharper警告的问题已在C 5.0和VB.Net 11.0中得到解决。以下是语言规范的摘录。请注意,在安装了Visual Studio 2012的计算机上,默认情况下可以在以下路径中找到规范

C:\Program Files x86\Microsoft Visual Studio 11.0\VB\Specifications\1033\Visual Basic语言规范.docx C:\Program Files x86\Microsoft Visual Studio 11.0\VC\Specifications\1033\CSharp Language Specification.docx C语言规范5.0版

8.8.4 foreach声明

v在while循环中的位置对于如何被嵌入语句中的任何匿名函数捕获非常重要

例如:

如果v是在while循环之外声明的,那么它将在所有迭代中共享,它在for循环之后的值将是最终值13,这就是f的调用将打印的值。相反,因为每个迭代都有自己的变量v,所以f在第一次迭代中捕获的变量将继续保持值7,这将被打印出来。注意:C的早期版本在while循环之外声明了v

Microsoft Visual Basic语言规范11.0版

10.9.3对于每个…下一个语句注释

该语言的10.0版和11.0版之间的行为略有变化。在11.0之前,没有为循环的每个迭代创建新的迭代变量。只有当迭代变量由lambda或LINQ表达式捕获,然后在循环后调用该表达式时,才能观察到这种差异

直到VisualBasic10.0,这在编译时产生了一个警告,并打印了3次。这是因为循环的所有迭代只共享一个变量x,并且所有三个lambda都捕获了相同的x,在执行lambda时,它保持了数字3。 从Visual Basic 11.0开始,它将打印1、2、3。这是因为每个lambda捕获不同的变量x


在演示之前,我必须对这段代码进行删减/简化。如果代码中有什么东西阻止你讨论这个问题,请告诉我。你希望在-C5或6中得到什么版本的产品?@乔里克:目前还没有发布任何C6产品。我们希望把这个补丁放在C5中。无论如何,我们都必须重新编译闭包重写代码,以使async/await工作,因此我认为最好同时修复此问题。@EricLippert更改是否需要更改C规范?@phoog,是的,绝对正确。它将改变编译器实现foreach的方式。看起来已经更新了。另请参见:@SolutionYogi在C4规范中搜索close和closure这个词的各种形式,我找不到任何描述闭合循环变量过程的内容。我不知道你的第一个链接的foreach循环的VS2003规范是如何发布的 万特。
int[] values = { 7, 9, 13 };
Action f = null;
foreach (var value in values)
{
    if (f == null) f = () => Console.WriteLine("First value: " + value);
}
f();
Dim lambdas As New List(Of Action)
For Each x In {1,2,3}
   lambdas.Add(Sub() Console.WriteLine(x)
Next
lambdas(0).Invoke()
lambdas(1).Invoke()
lambdas(2).Invoke()