modified closure warning in ReSharper

隐身守侯 提交于 2019-12-01 19:36:31

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);

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.

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.

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.

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!