使用声明中的“访问已关闭的封闭”警告

时间:2019-01-25 03:58:18

标签: c# resharper idisposable using-statement

我正在使用“使用声明”来确保StreamWriter被正确清理。

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

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

1 个答案:

答案 0 :(得分:2)

欢迎堆栈溢出。

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

在这种情况下,是否取决于所调用的ForEach方法。如果您要调用List.ForEach,那么您就不会构成延迟的执行链,因此fout显然对每次调用都有效。 ReSharper在使用这种方法时肯定应该更加了解。

但是还有其他ForEach方法,包括自定义方法,ReSharper可能不知道这些方法,或者实际上可能会延迟。如果编写得当,则它们将阻塞直到完成,但是我见过自定义的ForEach扩展方法。由于ReSharper不能确定,除非代码在action参数上使用InstantHandle注释告诉它,所以它会警告您。

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

一旦您确定此ForEach肯定会阻塞并且从不延误执行,则可以继续操作并取消警告:

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