C# ReSharper 警告 - 访问修改后的闭包

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1688465/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 19:59:56  来源:igfitidea点击:

ReSharper Warning - Access to Modified Closure

c#resharperwarnings

提问by Matt Grande

I have the following code:

我有以下代码:

string acctStatus = account.AccountStatus.ToString();
if (!SettableStatuses().Any(status => status == acctStatus))
    acctStatus = ACCOUNTSTATUS.Pending.ToString();

Note that account.AccountStatus is an enum of type ACCOUNTSTATUS. On the second line, ReSharper is giving me the warning "Access to Modified Closure" for acctStatus. When I do the recommended operation, Copy to local variable, it modifies the code to the following:

请注意, account.AccountStatus 是 ACCOUNTSTATUS 类型的枚举。在第二行,ReSharper 为 acctStatus 发出警告“访问修改后的闭包”。当我执行推荐的操作Copy to local variable 时,它将代码修改为以下内容:

string acctStatus = realAccount.AccountStatus.ToString();
string s = acctStatus;
if (!SettableStatuses().Any(status => status == s))
    acctStatus = ACCOUNTSTATUS.Pending.ToString();

Why is this better or preferable to what I had originally?

为什么这比我原来的更好或更可取?

EDIT

编辑

It also recommends Wrap local variable in array, which produces:

它还建议将局部变量包装在 array 中,这会产生:

string[] acctStatus = {realAccount.AccountStatus.ToString()};
if (!SettableStatuses().Any(status => status == acctStatus[0]))
    acctStatus[0] = ACCOUNTSTATUS.Pending.ToString();

This seems downright wacky to me.

这对我来说似乎非常古怪。

采纳答案by Godeke

The reason for the warning is that inside a loop you might be accessing a variable that is changing. However, the "fix" isn't really doing anything for you in this non-loop context.

警告的原因是在循环内您可能正在访问正在更改的变量。但是,在这种非循环上下文中,“修复”并没有真正为您做任何事情。

Imagine that you had a FOR loop and the if was inside it and the string declaration was outside it. In that case the error would be correctly identifying the problem of grabbing a reference to something unstable.

想象一下,你有一个 FOR 循环,if 在它里面,而字符串声明在它外面。在这种情况下,错误将正确识别获取对不稳定事物的引用的问题。

An example of what you don't want:

你不想要的一个例子:

string acctStatus

foreach(...)
{
  acctStatus = account.AccountStatus[...].ToString();
  if (!SettableStatuses().Any(status => status == acctStatus))
      acctStatus = ACCOUNTSTATUS.Pending.ToString();
}

The problem is that the closure will grab a reference to acctStatus, but each loop iteration will change that value. In thatcase it would be better:

问题是闭包将获取对 acctStatus 的引用,但每次循环迭代都会更改该值。在这种情况下,它会更好:

foreach(...)
{
  string acctStatus = account.AccountStatus[...].ToString();
  if (!SettableStatuses().Any(status => status == acctStatus))
      acctStatus = ACCOUNTSTATUS.Pending.ToString();
}

As the variable's context is the loop, a new instance will be created each time because we have moved the variable inside the local context (the for loop).

由于变量的上下文是循环,因此每次都会创建一个新实例,因为我们已将变量移到本地上下文(for 循环)中。

The recommendation sounds like a bug in Resharper's parsing of that code. However, in many cases this is a valid concern (such as the first example, where the reference is changing despite its capture in a closure).

该建议听起来像是 Resharper 解析该代码的错误。但是,在许多情况下,这是一个有效的问题(例如第一个示例,尽管在闭包中捕获了引用,但引用仍在更改)。

My rule of thumb is, when in doubt make a local.

我的经验法则是,当有疑问时,做一个本地人。

Here is a real world example I was bitten by:

这是我被咬的一个真实世界的例子:

        menu.MenuItems.Clear();
        HistoryItem[] crumbs = policyTree.Crumbs.GetCrumbs(nodeType);

        for (int i = crumbs.Length - 1; i > -1; i--) //Run through items backwards.
        {
            HistoryItem crumb = crumbs[i];
            NodeType type = nodeType; //Local to capture type.
            MenuItem menuItem = new MenuItem(crumb.MenuText);
            menuItem.Click += (s, e) => NavigateToRecord(crumb.ItemGuid, type);
            menu.MenuItems.Add(menuItem);
        }

Note that I capture the NodeType type local, note nodeType, and HistoryItem crumb.ItemGuid, not crumbs[i].ItemGuid. This ensures that my closure will not have references to items that will change.

请注意,我捕获了 NodeType 类型 local、注意 nodeType 和 HistoryItem crumb.ItemGuid,而不是 crumbs[i].ItemGuid。这确保我的闭包不会引用将更改的项目。

Prior to using the locals, the events would trigger with the current values, not the captured values I expected.

在使用 locals 之前,事件将使用当前值触发,而不是我期望的捕获值。