修改 ReSharper 中的关闭警告

发布于 2024-09-03 22:15:46 字数 703 浏览 5 评论 0原文

我希望有人能向我解释这段代码中可能会发生什么不好的事情,这会导致 ReSharper 给出“访问修改的闭包”警告:

bool result = true;

foreach (string key in keys.TakeWhile(key => result))
{
    result = result && ContainsKey(key);
}

return result;

即使上面的代码看起来安全,其他“修改的闭包”中可能会发生什么不好的事情实例?我经常在使用 LINQ 查询时看到此警告,但我倾向于忽略它,因为我不知道会出现什么问题。 ReSharper 尝试通过创建第二个对我来说似乎毫无意义的变量来解决问题,例如,它将上面的 foreach 行更改为:

bool result1 = result;
foreach (string key in keys.TakeWhile(key => result1))

Update: 在旁注上,显然整个代码块可以转换为以下语句,这会导致没有修改的闭包警告:

return keys.Aggregate(
    true,
    (current, key) => current && ContainsKey(key)
);

I was hoping someone could explain to me what bad thing could happen in this code, which causes ReSharper to give an 'Access to modified closure' warning:

bool result = true;

foreach (string key in keys.TakeWhile(key => result))
{
    result = result && ContainsKey(key);
}

return result;

Even if the code above seems safe, what bad things could happen in other 'modified closure' instances? I often see this warning as a result of using LINQ queries, and I tend to ignore it because I don't know what could go wrong. ReSharper tries to fix the problem by making a second variable that seems pointless to me, e.g. it changes the foreach line above to:

bool result1 = result;
foreach (string key in keys.TakeWhile(key => result1))

Update: on a side note, apparently that whole chunk of code can be converted to the following statement, which causes no modified closure warnings:

return keys.Aggregate(
    true,
    (current, key) => current && ContainsKey(key)
);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

故事灯 2024-09-10 22:15:46

在该特定代码中什么也没有,以以下为例:

int myVal = 2;

var results = myDatabase.Table.Where(record => record.Value == myVal);

myVal = 3;

foreach( var myResult in results )
{
    // TODO: stuff
}

看起来结果将返回值为 2 的所有记录,因为这是声明查询时 myVal 设置的值。但是,由于延迟执行,它实际上是值为 3 的所有记录,因为只有在迭代查询时才会执行查询。

在您的示例中,该值没有被修改,但 Resharper 警告您可能会被修改,并且延迟执行可能会给您带来问题。

In that particular code nothing, take the following as an example:

int myVal = 2;

var results = myDatabase.Table.Where(record => record.Value == myVal);

myVal = 3;

foreach( var myResult in results )
{
    // TODO: stuff
}

It looks like result will return all records where the Value is 2 because that's what myVal was set to when you declared the query. However, due to deferred execution it will actually be all records where the Value is 3 because the query isn't executed until you iterate over it.

In your example the value isn't being modified, but Resharper is warning you that it could be and that deferred execution could cause you problems.

同尘 2024-09-10 22:15:46

当您修改 result 变量时,闭包(在 lambda 表达式内使用该变量)将获取更改。

对于不完全理解闭包的程序员来说,这常常是一个意想不到的惊喜,因此 Resharper 对此提出了警告。

通过创建一个仅在 lambda 表达式中使用的单独 result1 变量,它将忽略对原始 result 变量的任何后续更改。

在您的代码中,您依靠闭包获取对原始变量的更改,以便它知道何时停止。

顺便说一句,不使用 LINQ 编写函数的最简单方法如下:

foreach (string key in keys) {
    if (ContainsKey(key))
        return true;   
}
return false;

使用 LINQ,您可以简单地调用 Any()

return keys.Any<string>(ContainsKey);

When you modify the result variable, the closure (the use of the variable inside the lambda expression) will pick up the change.

This frequently comes as an unexpected surprise to programmers who don't fully understand closures, so Resharper has a warning for it.

By making a separate result1 variable which is only used in the lambda expression, it will ignore any subsequent changes to the original result variable.

In your code, you're relying on the closure picking up the changes to the original variable so that it will know when to stop.

By the way, the simplest way to write your function without LINQ is like this:

foreach (string key in keys) {
    if (ContainsKey(key))
        return true;   
}
return false;

Using LINQ, you can simply call Any():

return keys.Any<string>(ContainsKey);
随波逐流 2024-09-10 22:15:46

请参阅

http:// ericlippert.com/2009/11/12/fitting-over-the-loop-variable-considered-harmful-part-one/

对此问题以及我们在假设的 C# 未来版本中可能做的事情进行了广泛的讨论来缓解它。

See

http://ericlippert.com/2009/11/12/closing-over-the-loop-variable-considered-harmful-part-one/

for an extensive discussion of this issue and what we might do in hypothetical future versions of C# to mitigate it.

傲性难收 2024-09-10 22:15:46

我不确定 ReSharper 是否会为此给出完全相同的警告,但下面说明了类似的情况。循环的迭代器在 LINQ 子句中使用,但直到循环完成之后才会实际计算该子句,此时迭代器变量已更改。下面是一个人为的示例,看起来应该打印从 1 到 100 的所有奇数,但实际上打印从 1 到 99 的所有数字。

var notEven = Enumerable.Range(1,100);
foreach (int i in Enumerable.Range(1, 50))
{
    notEven = notEven.Where(s => s != i * 2);
}

Console.WriteLine(notEven.Count());
Console.WriteLine(string.Join(", ", notEven.Select(s => s.ToString()).ToArray()));

这可能是一个很容易犯的错误。我听人们说过,如果你真正理解闭包/函数式编程/等等。你绝对不应该犯这个错误。我还看到确实很好地掌握了这些概念的专业开发人员犯了同样的错误。

I'm not sure if ReSharper will give the exact same warning for this, but the following illustrates a similar situation. The iterator for a loop is used in a LINQ clause, but the clause isn't actually evaluated until after the loop has finished, by which time the iterator variable has changed. The following is a contrived example that looks like it should print all odd numbers from 1 to 100, but actually prints all numbers from 1 to 99.

var notEven = Enumerable.Range(1,100);
foreach (int i in Enumerable.Range(1, 50))
{
    notEven = notEven.Where(s => s != i * 2);
}

Console.WriteLine(notEven.Count());
Console.WriteLine(string.Join(", ", notEven.Select(s => s.ToString()).ToArray()));

This can be quite an easy mistake to make. I've heard people say that if you truly understand closures/functional programming/etc. you should never make this mistake. I've also seen professional developers who certainly do have a good grasp of those concepts make this exact mistake.

山田美奈子 2024-09-10 22:15:46

嗯,警告是因为 result 可能会在执行闭包之前更改(变量是在执行时获取的,而不是定义时获取的)。就您而言,您实际上是在利用这一事实。如果您使用 resharper recomodation,它实际上会破坏您的代码,如 key =>; result1 始终返回 true。

Well, the warning is because result could be changed before the closure is executed (variables are taken at execution, not defition). In your case, you are actually taking advantage of that fact. If you use the resharper reccomodation, it will actually break your code, as key => result1 always returns true.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文