访问修改后的闭包,这是一个ReSharper错误吗?

时间:2010-04-07 10:40:05

标签: c# lambda resharper closures

我有最新的ReSharper 5.0版本(1655),我在下面的代码中遇到了“访问修改后的闭包”的建议:

var now = new DateTime(1970, 1, 1);
var dates = new List<DateTime>();
dates.Where(d => d > now);
...
now = new DateTime();

并且lambda表达式中的now带有警告下划线。

我很确定这是一个ReSharper错误,但它真的是吗?

编辑:我应该检查得更好,代码后面有now的作业。

编辑2 Jon Skeet的answer几乎可以解答这个问题,但以下内容如何:

var query = dates.Where(d => d > now).ToList();

这不应该通过立即执行查询来解决问题吗?

3 个答案:

答案 0 :(得分:4)

是的,现在你已经修改了这个问题,这是完全合理的。您正在修改闭包中使用的变量 - 这会产生意外结果:

var now = new DateTime(1970, 1, 1);
var dates = new List<DateTime>();
var query = dates.Where(d => d > now);
...
now = new DateTime(1990, 1, 1);
foreach (DateTime date in query)
{
    // This will only see dates after 1990, not after 1970
    // This would confuse many developers.
}

事实上,这不仅仅是查询何时开始 - 您可以在迭代结果时修改

var now = new DateTime(1970, 1, 1);
var dates = new List<DateTime>();
var query = dates.Where(d => d > now);
...
foreach (DateTime date in query)
{
    now = date;
    Console.WriteLine(date);
}

这会给出严格增加的日期序列......再次,有些令人困惑。

对于这一点,R#是绝对正确的,IMO。它有时有用 - 但应谨慎使用。

答案 1 :(得分:1)

ReSharper警告你的是now的值是在lambda表达式中捕获的,而不是你认为执行lambda时的值。

要解决您的问题,您需要在使用之前将now的值分配给局部变量:

var now = new DateTime(1970, 1, 1);
var dates = new List<DateTime>{new DateTime(2001, 12, 12)};
DateTime localNow = now;
dates.Where(d => d > localNow);

now = new DateTime(2003, 12, 12);

如果您想阅读更多内容,ReSharper论坛上会有一个post,其中包含几个链接以及进一步说明。

答案 2 :(得分:0)

这不是resharper,认为你正在修改集合的内容,而最有可能是dates。你可以放心地忽略这一点。