是“访问修改后的闭包”吗?通过理解语法解决?
ReSharper 6.0 针对第一个代码片段中的 dr
标识符向我发出“访问修改后的闭包”警告。
private IEnumerable<string> GetTheDataTableStrings(DataTable dt) {
foreach (DataRow dr in dt.Rows) {
yield return GetStringFuncOutput(() => dr.ToString());
}
}
我想我对这个警告试图保护我的内容有一个基本的了解:在询问 GetTheDataTableStrings 的输出之前 dr
会多次更改,因此调用者可能无法获得我期望的输出/行为。
但 R# 没有对第二个代码片段发出任何警告。
private IEnumerable<string> GetTheDataTableStrings(DataTable dt) {
return from DataRow dr in dt.Rows select GetStringFuncOutput(dr.ToString);
}
使用理解语法时,我可以安全地放弃此警告/担忧吗?
其他代码:
string GetStringFuncOutput(Func<string> stringFunc) {
return stringFunc();
}
ReSharper 6.0 gives me the "Access to modified closure" warning for the dr
identifier in the first code snippet.
private IEnumerable<string> GetTheDataTableStrings(DataTable dt) {
foreach (DataRow dr in dt.Rows) {
yield return GetStringFuncOutput(() => dr.ToString());
}
}
I think I have a basic understanding of what this warning is trying to protect me from: dr
changes several times before GetTheDataTableStrings's output is interrogated, and so the caller might not get the output/behavior I expect.
But R# doesn't give me any warning for the second code snippet.
private IEnumerable<string> GetTheDataTableStrings(DataTable dt) {
return from DataRow dr in dt.Rows select GetStringFuncOutput(dr.ToString);
}
Is it safe for me to discard this warning/concern when using the comprehension syntax?
Other code:
string GetStringFuncOutput(Func<string> stringFunc) {
return stringFunc();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先,您对第一个版本的担忧是正确的。该 lambda 创建的每个委托都通过相同的变量关闭,因此当该变量发生变化时,查询的含义也会发生变化。
其次,仅供参考,我们很可能在下一版本的 C# 中修复此问题;这是开发者的一大痛点。
(更新:这个答案是在 2011 年写的。事实上,我们确实采用了 C# 5 中描述的修复。)
在下一个版本中,每次运行“foreach”循环时,我们都会生成一个新循环变量而不是每次都关闭同一个变量。这是一个“破坏性”更改,但在绝大多数情况下,“破坏”将修复而不是导致错误。
“for”循环不会改变。
请参阅 http://有关详细信息,请访问 ericlippert.com/2009/11/12/ opening-over-the-loop-variable-considered-harmful-part-one/。
第三,查询理解版本没有问题,因为没有正在修改的封闭变量。查询理解形式与您所说的相同:
lambda 不对任何外部变量封闭,因此不会意外修改变量。
First off, you are correct to be concerned about the first version. Each delegate created by that lambda is closed over the same variable and therefore as that variable changes, the meaning of the query changes.
Second, FYI we are highly likely to fix this in the next version of C#; this is a major pain point for developers.
(UPDATE: This answer was written in 2011. We did in fact take the fix described below in C# 5.)
In the next version each time you run through the "foreach" loop we will generate a new loop variable rather than closing over the same variable every time. This is a "breaking" change but in the vast majority of cases the "break" will be fixing rather than causing bugs.
The "for" loop will not be changed.
See http://ericlippert.com/2009/11/12/closing-over-the-loop-variable-considered-harmful-part-one/ for details.
Third, there is no problem with the query comprehension version because there is no closed-over variable that is being modified. The query comprehension form is the same as if you'd said:
The lambda is not closed over any outer variable, so there is no variable to be modified accidentally.
Resharper 警告的问题已在 C# 5.0 和 VB.Net 11.0 中得到解决。以下是语言规范的摘录。请注意,在安装了 Visual Studio 2012 的计算机上,默认情况下可以在以下路径中找到规范。
C# 语言规范版本 5.0
8.8.4 foreach 语句
Microsoft Visual Basic 语言规范版本 11.0
10.9.3 For Each...Next 语句(注释)
The issue that Resharper is warning about has been resolved in both C# 5.0 and VB.Net 11.0. The following are extracts from the language specifications. Note that the specifications can be found in the following paths by default on a machine with Visual Studio 2012 installed.
C# Language Specification Version 5.0
8.8.4 The foreach statement
The Microsoft Visual Basic Language Specification Version 11.0
10.9.3 For Each...Next Statements (Annotation)