当构造失败时如何处置类字段
本文关键字:何处置 字段 失败 | 更新日期: 2023-09-27 18:16:20
假设我有一个类,它有两个字段,每个字段都包含一次性对象。
class C : IDisposable {
private IDisposable thing1 = new Thing1();
private IDisposable thing2 = new Thing2();
... IDisposable implementation ...
}
创建类C
的实例时,将先创建Thing1
,然后创建Thing2
。但是,如果在构造Thing2
时发生异常,则不会创建它,并且类C
的实例也不会完成创建。实例化类C
的代码没有对部分构造的C
的引用来调用Dispose
,所以我们留下了一个永远不会被处置的Thing1
的实例。
最好的分辨率是多少?
您可以将初始化代码移动到构造函数中,然后将整个构造函数包装在一个try/catch
块中,该块处理所有拥有的对象并重新抛出异常。
在c++/CLI中,可以通过单个声明指定如何定义、初始化和清除字段。在vb.net中,可以设计一个基类,使子类能够做同样的事情,例如
Dim MyBitmap as Bitmap = Acquire(new Bitmap(Params.FileName))
其中Params
是一个对象,其中存储了一些构造函数参数(如FileName
)。Acquire
方法(在基类中定义)将把对新创建的IDisposable
的引用添加到一个列表中,如果构造函数抛出该列表,则应该清理该列表。
ThreadStatic
字段来跟踪创建的对象,但这有点麻烦。在实践中,最好的方法可能是定义Dispose
,以便正确地处理部分构造的对象,并让每个构造函数包含如下代码:bool success = false;
try
{
...initialize stuff
success = true;
}
finally
{
if (!success)
Dispose();
}
注意,因为Dispose()
是虚的,它可能被调用多次。此外,由于子类Dispose
方法可能在子类构造函数没有运行的情况下被调用,因此每个Dispose
层都需要为这种可能性做好准备。