C#IDisposable模式并抛出ObjectDisposedException

时间:2014-07-05 07:27:53

标签: c# dispose objectdisposedexception

给大家一个问题。

在我的公司,我们正在开发一个在微软MVC框架内运行的应用程序。 我们正在实现的控制器类继承自 MVC基类Controller 。例如:

public class MyController: Controller
{
    protected bool IsDisposed { get; set; }
… various methods…
 }

我们在团队中的讨论围绕Dispose()模式。从本质上讲,这涉及实现IDisposable接口,最好是根据Microsoft认可的模式。

例如,请参阅此链接:http://msdn.microsoft.com/en-us/library/fs2xkftw%28v=vs.110%29.aspx

有趣的是,我们的控制器类不拥有任何资源,无论是托管还是托管。结果,Dispose(bool)的实现大大简化了:

protected override void Dispose(bool disposing)
{
    IsDisposed = true;
    base.Dispose(disposing);
}

IsDisposed属性的使用(或需要)存在一些分歧,该属性在以下方法中使用:

protected void ThrowIfDisposed()
{
    if (IsDisposed) throw new ObjectDisposedException(“MyController”);
}

然后在每个执行“实际”工作的方法的开头调用此方法。这里的想法是不应该再次使用被处置的对象,因此它应该抛出ObjectDisposedException。另一种意见是,因为Dispose(bool)做“没有”(除了设置IsDisposed属性并在基类上调用Dispose(bool)),“处置”对象实际上不是状态不可用,所以没有理由抛出。因此,没有理由甚至实施Dispose(bool)

反对这一点的论点是,MyController在处理它时会抛出并调用其中一个方法,因此在未来的版本中,如果添加了托管和/或非托管资源,它的行为就不会改变。

反对这最后一点的论点是MyController永远不应该在将来的版本中添加任何资源,而是应该在未来需要添加资源的情况下派生它。另一个问题是:为什么(库)类控制器没有实现ThrowIfDisposed()或类似的东西?

所以,总结一下,派系想要实现Dispose(bool)ThrowIfDisposed()如上所示,派系二认为它们是不必要的并且想要废除它们。

我在两个观点中都看到了优点,无法真正下定决心。意见?

3 个答案:

答案 0 :(得分:8)

  

有趣的是,我们的控制器类不拥有任何管理或管理的资源。

然后你不需要IDisposable模式。

  

然后在每个执行“实际”工作的方法的开头调用此方法[ThrowIfDisposed()]。

这里的问题是:为什么?

如果您确实想要跟踪可用/已放弃状态,则不要将其称为IsDisposed。

  

为什么(库)类控制器没有实现ThrowIfDisposed()或类似的东西?

因为没用。

回到开头:为什么有人认为这是必要的?它的用途是什么? 看来你可以把它撕掉。

答案 1 :(得分:1)

如果某个对象在处置后收到请求,则不应该因ObjectDisposedException 以外的任何原因而失败 - 这意味着它不应该导致{{1} ,产生垃圾数据,使系统崩溃,或做任何其他此类事情。这并不意味着请求不应该成功 - 只是NullReferenceException应该是唯一的失败模式。

对于ObjectDisposedException,在大多数情况下我无法真正看到它的用处。不知道对象是否被处置的代码通常对对象的状态知之甚少,以了解它是否可能由于某些其他原因而无法使用;因此,不知道对象是否被处置的代码通常不应该对它做任何事情,除非 - 在某些情况下 - 对IsDisposed它,以及在大多数情况下想要在某个对象上调用Dispose,如果它尚未被处置,则应该无条件地调用Dispose。使用方法Dispose可能会有一些价值,它会为具有非平凡MayNeedDisposing方法的对象返回true,直到它们被处理掉,但这样的方法可以无条件地返回Dispose用于具有空false方法的对象[在类例如的情况下]注册一个回调纯粹是为了在某事上调用Dispose,事先测试Dispose可能是一个有用的优化。

最后,关于类或接口是应该实现还是继承MayNeedDisposing,问题不在于类型本身是否获取资​​源,而在于是否可以存储对获取资源的某些内容的最后存活引用在那种类型。例如,尽管绝大多数IDisposable实现都没有获取资源,但有些实现了,并且在许多这种情况下,对这些对象的唯一引用将存储在IEnumerator<T>类型的变量中,由代码持有,不知道有问题的对象是否有任何资源。请注意,非通用IEnumerator<T>不会实现IEnumerator,但某些实现会获取资源。因此,如果实现IDisposable,则调用IEnumerable.GetEnumerator的代码将需要在返回的枚举器上调用DisposeIDisposable没有继承IEnumerator的事实并不能解除接收IDisposable实现的代码,该实现也会从调用{{IEnumerator的职责中实现IDisposable 1}} - 它只会使这些代码更难以履行这一责任。

答案 2 :(得分:0)

派系二是绝对正确的。不要这样做。

以所描述的方式实施IDisposable并且出于给出的理由违反了至少三个良好原则。

  1. 你不需要它。 http://c2.com/cgi/wiki?YouArentGonnaNeedIt
  2. 做最简单的事情。 http://www.xprogramming.com/Practices/PracSimplest.html
  3. 保持简单愚蠢。 https://en.wikipedia.org/wiki/KISS_principle
  4. 每个级别都错了。不要这样做。