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

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

基础构造函数是否有责任将其主体包装在try / catch中,以确保在exception的情况下正确处理IDisposable事物?

相关问题:

  • CA2000在C#中将对象引用传递给基础构造函数
  • 通过构造函数链传递IDisposable对象

这不是问题的答案,但……

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

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

虽然CA2000分析如此破碎,但完全禁用它可能更有用。

是的,既不是类构造函数,也不是在构造函数中using语句调用Dispose。

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

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

 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; } 

遵循的简单规则:如果您创建*它,您有责任看到它被处置掉。 相反,如果一个方法(无论是构造函数还是其他方法)不能创建一次性对象,我就不会期望它处理它。 (* 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不会调用参数化基础。

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

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

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