假设我有一个包含两个字段的类,每个字段都包含一次性对象。
class C : IDisposable {
private IDisposable thing1 = new Thing1();
private IDisposable thing2 = new Thing2();
... IDisposable implementation ...
}
创建类C
Thing1
的实例时,将创建,然后Thing2
。但是,如果在构造Thing2
时发生异常,则不会创建它,并且类C
的实例也不会完成。实例化类C
的代码没有引用部分构造的C
来调用Dispose
,因此我们留下了Thing1
的实例从来没有被处置过。
什么是最佳分辨率?
答案 0 :(得分:3)
您可以将初始化代码移动到构造函数,然后将整个构造函数包装在try/catch
块中,该块处理所有拥有的对象并重新抛出异常。
答案 1 :(得分:1)
在C ++ / CLI中,单个声明可以指定如何定义,初始化和清理字段。在vb.net中,可以设计一个基类,使子类能够做到这一点,例如。
Dim MyBitmap as Bitmap = Acquire(new Bitmap(Params.FileName))
其中Params
是一个对象,其中存储了一些构造函数参数(如FileName
)。 Acquire
方法(在基类中定义)将对新创建的IDisposable
的引用添加到应该在构造函数抛出时清理的事物列表。
不幸的是,C#不利于任何一种模式。最接近的可能是定义一些静态方法,这些方法使用ThreadStatic
字段来跟踪创建的对象,但这有点icky。在实践中,最好的方法可能是定义Dispose
以便正确使用部分构造的对象,并使每个构造函数包含如下代码:
bool success = false;
try
{
...initialize stuff
success = true;
}
finally
{
if (!success)
Dispose();
}
请注意,由于Dispose()
是虚拟的,因此可能会多次调用它。另外,因为子类Dispose
方法可能在没有运行子类构造函数的情况下被调用,所以每个Dispose
层都需要为这种可能性做好准备。