如果我使用base(...)
构造将IDisposable对象传递给基类构造函数,我会在FxCop中触发silly error关于放松IDisposable
。警告偶尔在其他地方有用,所以我不想禁用它,但我意识到我不知道我应该使用的确切语义。
基础构造函数是否有责任将其主体包装在try / catch中,以确保在发生异常时正确处理IDisposable
事物?
相关问题:
答案 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字段的声明和初始化,并确保它们即使在构造函数失败。代码可以使用一点清理,但这似乎是适当的。
我无法弄清楚如何做的一件事还包括事件设置/清理。拥有已分配的对象列表不会转换为需要展开的事件订阅列表,即使是通过反射也是如此。