我最近才开始在我们的几个项目中使用完整的代码分析规则集。真正让我更仔细地思考 IDisposable
类的警告之一是 CA2000 .我有很多这样的例子,提示一些一次性对象没有在每个异常路径上处理。
因此问题是:在返回之前,如果方法的其余部分出现异常,处理对象处置的更正确方法是什么?例如,这个方法:
public MyDisposable GetMyDisposable()
{
var disposable = new MyDisposable();
disposable.MethodThatCanThrowExceptions();
return disposable;
}
会引发这样的警告,因为如果 MethodThatCanThrowExceptions
方法确实抛出异常,调用者将不会收到一次性实例,因此在垃圾收集器启动之前没有人能够处理它中。
我一直在使用的模式是这样的:
public MyDisposable GetMyDisposable()
{
var disposable = new MyDisposable();
try
{
disposable.MethodThatCanThrowExceptions();
}
catch
{
disposable.Dispose();
throw;
}
return disposable;
}
但我看到一些人提到使用 finally
block 而不是 catch,使用 bool 值表示其余代码中存在问题,如下所示:
public MyDisposable GetMyDisposable()
{
bool ok;
var disposable = new MyDisposable();
try
{
disposable.MethodThatCanThrowExceptions();
ok = true;
return disposable;
}
finally
{
if (!ok) disposable.Dispose();
}
}
在这两者之间,处理这种情况的最佳方法是什么?有没有其他更简单的方法来处理这种情况?我用 C++ 编写了一些程序,在这种语言中,通常使用一个类来处理这些一次性情况,称为范围保护。据我所知,该模式支持 Release
方法,因此您可以用处置行为包装代码,但在某些情况下取消实际处置。在 C# 中,我假设它看起来像这样:
public MyDisposable GetMyDisposable()
{
using (var disposable = new MyDisposable())
{
disposable.MethodThatCanThrowExceptions();
return release disposable;
}
}
我知道 C# 中不存在这样的东西,但如果有类似或干净的东西就好了。
最佳答案
在这种特定情况下(我可能会补充说这是相当不寻常的),当您返回一次性资源时,您将处理对象的责任从该方法传递给它的调用者。
显然,返回一个已处置的对象对调用者来说毫无意义,因为他们永远无法使用它。这排除了此处的最后一个选项。
您想在无法正确初始化对象的情况下处置该对象,这意味着在出现异常时处置该对象,这正是您的第一个提案以最直接的方式所做的.您的第二种方法与您的第一种方法的功能相同,只是在操作过程中不是那么简单。
finally
block (为简单起见通常隐藏在 using
中)在有负责处理资源的方法以及生命周期的地方时是合适的一次性资源的范围与您存储它的变量的范围相同。绝大多数一次性资源的使用情况往往都是这种情况,只是这一次不是特别的情况。
关于c# - 如何在出现异常时正确处理可能被淘汰的类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25430008/