【问题标题】:"Access to disposed closure" warning in using statementusing 语句中的“访问已处置的闭包”警告
【发布时间】:2019-01-25 03:58:18
【问题描述】:

我正在使用“using 语句”来确保 StreamWriter 被正确清理。

using (StreamWriter fout = new StreamWriter(tempFile))
{
    data.ForEach(line => fout?.WriteLine(line));
}

我收到 ReSharper 警告“访问已处置的闭包”,据我了解,这是因为变量 fout 可能已关闭。我了解在某些用途中可能会发生这种情况,但在这种情况下,fout 是否可能在调用 WriteLine 时已经被处置?

【问题讨论】:

  • 确切的答案是它完全取决于ForEach 方法在内部对给定委托所做的事情。我和你都知道这不会发生,但编译器无法确定,因此发出警告。
  • 只要在使用后关闭流,在没有 using 语句的情况下对其进行编码应该不会有任何问题。但是是的,如果你不关闭它,它会导致许多程度的痛苦
  • 这看起来像是 Resharper 警告,而不是编译器警告(您可能已经提到过)。我相信它的意思是传递给ForEach 的 lambda 委托有一个闭包,其中包含将由 Using 释放的变量。如果 ForEach 缓存了委托,它将在可能已被释放后访问fout。通读resharper-support.jetbrains.com/hc/en-us/community/posts/…。最后一篇文章(我认为是来自 Resharper 的人)主要解释了它

标签: c# resharper idisposable using-statement


【解决方案1】:

欢迎来到 Stack Overflow。

ReSharper 的 Access to disposed closure 警告仅应在 LINQ 延迟执行捕获对可能在执行之前释放的闭包的引用时发生。

这里是否是这种情况取决于您调用的ForEach 方法。如果您正在调用List.ForEach,那么您并没有构成延迟执行链,因此fout 显然对每次调用都有效。 ReSharper 应该更了解这种方法。

但还有其他 ForEach 方法,包括自定义方法,ReSharper 可能不知道或者实际上可能会延迟。如果它们写得很好,那么它们会阻塞直到它们完成,但我见过自定义的 ForEach 扩展方法没有。由于 ReSharper 无法确定,除非代码通过操作参数上的 InstantHandle 注释告诉它,它会警告您。

如果您在这里使用List.ForEach,那么我建议您放弃它,转而使用旧的foreach 声明。对于其他扩展,请确定它是否阻塞,或者在任何情况下它是否有可能推迟执行。 Observable.ForEachParallel.ForEach 似乎都阻止执行,直到集合被完全处理或事件源关闭。其他代码可能不会这样做,并且事后追踪这样的错误可能会很痛苦。如果可以,请检查方法的源代码,如果无法访问源代码,请联系库开发人员。

一旦您确定此 ForEach 肯定会阻止并且永远不会延迟执行,那么您可以继续并取消警告:

// ReSharper disable AccessToDisposedClosure
data.ForEach(line => fout?.WriteLine(line));
// ReSharper restore AccessToDisposedClosure

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多