如果初始化失败,如何将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也是如此。