施工失败时如何处理类字段?

时间:2013-06-02 03:46:29

标签: c# idisposable

假设我有一个包含两个字段的类,每个字段都包含一次性对象。

    class C : IDisposable {

            private IDisposable thing1 = new Thing1();
            private IDisposable thing2 = new Thing2();

               ... IDisposable implementation ...
    }

创建类C Thing1的实例时,将创建,然后Thing2。但是,如果在构造Thing2时发生异常,则不会创建它,并且类C的实例也不会完成。实例化类C的代码没有引用部分构造的C来调用Dispose,因此我们留下了Thing1的实例从来没有被处置过。

什么是最佳分辨率?

2 个答案:

答案 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层都需要为这种可能性做好准备。