为啥 Resharper 将此标记为“访问修改后的闭包”?

Posted

技术标签:

【中文标题】为啥 Resharper 将此标记为“访问修改后的闭包”?【英文标题】:Why does Resharper flag this as "access to modified closure"?为什么 Resharper 将此标记为“访问修改后的闭包”? 【发布时间】:2017-01-26 08:17:33 【问题描述】:

如果这是一个重复的问题,我很抱歉。我在这里看到很多关于“修改后的闭包”的问题,但似乎没有一个能解决我所看到的问题。

Resharper 2016.2 将我在 lambda 表达式中使用的“b”和“i1”标记为“访问修改后的闭包”。我认为不应该。我从不在程序的其他任何地方使用 b 或 i 或 i1 。两者都在循环中声明——事实上,i1 是由 Resharper 创建的,用于解决 i 修改后的闭包问题。我可以尝试用 i1 解决它,它只会创建一个“int i2 = i1”,并且仍然会在 i2 上给我警告!这肯定是不对的。我在这里错过了什么?

for (int i = 0; i < 10; ++i) 
    Button b = new Button();
    int i1 = i;
    Invoker.SyncInvoke(b, () =>  b.Text = "number " + i1; );

编辑: 这必须是一个错误。在某个源文件中的某一点(准确地说是第 424 行)是以下三行:

        var collapsed = daSheet;
        int numrows = collapsed.GetLastNonEmptyRow(NonEmptyItemFlag.Data);
        int numcols = collapsed.GetLastNonEmptyColumn(NonEmptyItemFlag.Data);

如果我在这些行之前粘贴上面的 sn-p(上面的 for 循环),我不会收到任何警告。如果我在这些行之后粘贴它,我会收到关于“b”和“i1”的警告。如果我将它粘贴在第 2 行和第 3 行之间,我会收到有关“i1”的警告,但不会收到 b。这没有任何意义。

【问题讨论】:

没有冒犯 Resharper 的许多聪明人,但是他们的一些分析仪的误报率非常可怕。我不认为你缺少任何东西。我认为这不是一个很好的分析器。 Invoker.SyncInvoke的使用是多余的;正在创建按钮并分配文本,但尚未将按钮添加到控件集合中。 如果这段代码是一个简化的例子,它可能被简化了太多,虽然很难确定。 这是导致问题的确切 sn-p 吗?因为如果我将它粘贴到一个新项目中(并创建 Invoker 类),我根本不会收到警告。 是的,这就是确切的 sn-p,是的,它过于简单化了。使问题出现的最低限度。奇怪的是,如果我将它粘贴到一个新项目或任何较小的项目中,我不会收到警告,但如果我将它粘贴到我的大项目中,我会收到。每次。任何地方都没有其他变量或任何称为“b”或“i1”的东西。 【参考方案1】:

“他们的一些分析仪的误报率非常糟糕” - 你是对的^^

事实上,Resharper 并没有那么错。

想象一下,而不是 Invoker... 你会像这样使用 Task.Startnew(...) 我会假设(仅阅读源代码)执行后你没有 10 个不同的按钮,你只有一个,而这个有文本“数字 9”。

因为编译器将 lambda 表达式中的按钮和 i1 参数放在一起,所以通常值得用 dotpeek 查看反编译的源代码 ?

【讨论】:

你错了。您肯定会有 10 个按钮,因为您调用了 10 次“new Button()”。如果您在 lambda 中使用循环计数器“i”,则所有按钮都会(或可能,取决于代码实际执行的时间)说“按钮 9”。创建一个局部范围的变量(被 lambda 捕获)使其正常工作。 Resharper 对此有误。

以上是关于为啥 Resharper 将此标记为“访问修改后的闭包”?的主要内容,如果未能解决你的问题,请参考以下文章

修改 ReSharper 中的关闭警告

C++ 的 ReSharper [关闭]

如何升级到 C# 5.0?访问修改后的闭包

访问修改后的闭包 - 为啥这是一个建议的修复?

Resharper 将我的 NUnit 测试标记为未使用

为啥 ReSharper 告诉我“隐式捕获的闭包”?