【问题标题】:Access to modified closure, is this a ReSharper bug?访问修改后的闭包,这是 ReSharper 错误吗?
【发布时间】:2011-02-05 04:59:21
【问题描述】:

我有最新的 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

EDIT 2 下面 Jon Skeet 的 answer 几乎回答了这个问题,但以下内容呢:

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

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

【问题讨论】:

  • 只是在那个代码上?在这些行之后没有分配给“现在”?
  • @Jon Skeet 你说得对,几行后面有一个作业!我会修改问题。

标签: c# lambda resharper closures


【解决方案1】:

好的,现在您已经修改了问题,这完全有道理。您正在修改闭包中使用的变量 - 这可能会产生意想不到的结果:

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。它有时很有用 - 但应谨慎使用。

【讨论】:

  • 如果我调用ToList(),这不应该立即执行查询,从而防止出现这种情况吗?
  • @hmemcpy:警告仍然存在,因为 R# 不知道闭包不再使用。了解每个可能使用闭包的方法是否意味着? R# 不知道ToList() 会立即执行查询然后丢弃源代码。
【解决方案2】:

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,其中包含几个链接以及进一步的解释。

【讨论】:

    【解决方案3】:

    不,这更清楚地认为您正在修改集合的内容,同时循环它,dates 很可能。您可以放心地忽略这一点。

    【讨论】:

    • 由于now 是一个捕获的变量,因此在评估查询之前对其进行的任何更改很可能会产生与预期不同的结果,这正是 R# 试图强调的。
    • 嗯显然问题已更改为他确实使用循环的代码
    猜你喜欢
    • 2015-11-08
    • 2010-12-13
    • 1970-01-01
    • 2011-09-29
    • 2017-01-26
    • 2011-07-28
    • 2010-09-23
    • 1970-01-01
    相关资源
    最近更新 更多