异常情况下如何正确处置潜在的孤立类?
作者:互联网
我最近刚开始在我们的一些项目中使用“代码分析”的完整规则集.确实使我对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块而不是catch,并使用布尔值表示其余代码中存在问题,如下所示:
public MyDisposable GetMyDisposable()
{
bool ok;
var disposable = new MyDisposable();
try
{
disposable.MethodThatCanThrowExceptions();
ok = true;
return disposable;
}
finally
{
if (!ok) disposable.Dispose();
}
}
在这两者之间,处理这种情况的最佳方法是什么?还有其他可能更简单的方法来处理这种情况吗?我用C编程了一下,用这种语言通常是使用一个类来处理这些一次性情况,称为Scope Guard.据我所知,该模式支持Release方法,因此您可以包装具有处置行为的代码,但在某些情况下取消实际处置.在C#中,我假设它看起来像这样:
public MyDisposable GetMyDisposable()
{
using (var disposable = new MyDisposable())
{
disposable.MethodThatCanThrowExceptions();
return release disposable;
}
}
我知道这样的东西在C#中不存在,但是如果有等同的东西或干净的东西会很好.
解决方法:
在这种特定情况下(我可能会添加这种情况,这可能是非常不寻常的),当您返回一次性资源时,您将负责将对象从此方法处置的责任传递给其调用者.
显然,对于调用者来说,返回已经被处置的对象将毫无意义,因为他们将永远无法使用它.那排除了这里的最后一个选择.
您希望在无法正确初始化对象的情况下处置该对象,这意味着在存在异常的情况下处置该对象,这正是您第一个建议以最直接的方式所做的事情.您的第二种方法的功能与第一种方法相同,只是执行起来并不那么简单.
当存在负责处理资源的方法并且一次性资源的生存期与要存储的变量的范围相同时,使用finally块(为简单起见通常隐藏在use内部)是合适的.绝大多数可使用资源的使用都是这种情况,特别是不是这种情况.
标签:raii,dispose,using-statement,c 来源: https://codeday.me/bug/20191121/2051117.html