如果初始化失败,如何将IDisposable对象传递给在C#中处理的基础构造函数参数?

时间:2010-10-20 14:07:10

标签: c# idisposable

如果我使用base(...)构造将IDisposable对象传递给基类构造函数,我会在FxCop中触发silly error关于放松IDisposable。警告偶尔在其他地方有用,所以我不想禁用它,但我意识到我不知道我应该使用的确切语义。

基础构造函数是否有责任将其主体包装在try / catch中,以确保在发生异常时正确处理IDisposable事物?

相关问题:

4 个答案:

答案 0 :(得分:4)

不是问题的答案,但是......

您不一定需要完全禁用该规则 - 您可以针对您知道分析过度热衷的方法禁止它:

[SuppressMessage("Microsoft.Reliability",
                 "CA2000:DisposeObjectsBeforeLosingScope",
                 Justification = "Your reasons go here")]
public YourClass(IDisposable obj) : base(obj)
{
}

虽然CA2000分析所以已破坏,但完全禁用它可能更有用。

答案 1 :(得分:2)

是的,类构造函数和using语句都不会在构造函数中出现异常时调用Dispose。

在构造函数中处理异常是你的工作,因为尚未创建的对象不能以与成功创建的对象相同的方式“处置”。

这与基础构造函数没有关系,这是一个更大的问题:

class A: IDisposable
{
    public A() // constructor
    {
        r1 = new Resource(res1_id);     // resource aquisition 
        r2 = new Resource(res2_id);     // assume exception here
    }

    public void Dispose()
    {
        r1.Release();           // released successfully
        r2.Release();           // what to do?
    }

    Resource r1, r2;
}

答案 2 :(得分:1)

遵循的简单规则:如果您创建*它,您有责任看到它被处置掉。相反,如果一个方法(无论是构造函数还是其他方法)不能创建一次性对象,我不希望它处理它。 (* Creation包括调用返回IDisposable的方法。)

所以给出像

这样的东西
public Foo(SomeDisposable obj) : base(obj) { }

我希望看到像

这样的东西
using (SomeDisposable obj = new SomeDisposable())
{
    Foo foo = new Foo(obj);
}

而不是

Foo foo = new Foo(new SomeDisposable());

如果你有一个Foo的无参数构造函数,并且你想用一次性对象调用基础构造函数,那么你处于一个更棘手的位置,这可能是规则进入的地方保护你。我会说通过编写基础来创建并因此负责IDisposable或者在具有IDisposable参数的构造函数之间进行1:1映射来避免这样的位置,这样无参数Foo不会调用参数化基础。

但不应该是方法或构造函数的工作来猜测你完成了传入的对象,因为它应该如何知道?你可以有其他用途。

答案 3 :(得分:0)

我想出了一个很好的模式,我将其作为我自己的相关问题here的答案,它允许我们安全地结合iDisposable字段的声明和初始化,并确保它们即使在构造函数失败。代码可以使用一点清理,但这似乎是适当的。

我无法弄清楚如何做的一件事还包括事件设置/清理。拥有已分配的对象列表不会转换为需要展开的事件订阅列表,即使是通过反射也是如此。