【问题标题】:C# IDisposable pattern and throwing ObjectDisposedExceptionC# IDisposable 模式和抛出 ObjectDisposedException
【发布时间】:2014-07-05 07:27:53
【问题描述】:

问大家一个问题。

在我的公司,我们正在开发一个在 Microsoft 的 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)),“disposed”对象并没有真正处于不可用的状态,所以没有理由扔。因此,甚至没有理由实现Dispose(bool)

反对这一点的一个论点是 MyController 应该在它被释放并调用它的一个方法时抛出,以便在将来的版本中添加托管和/或非托管资源时它的行为不会改变。

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

所以,综上所述,派系一想实现Dispose(bool)ThrowIfDisposed()如上图,派系二认为它们没有必要并想取消它们。

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

【问题讨论】:

    标签: c# dispose objectdisposedexception


    【解决方案1】:

    有趣的是,我们的控制器类不拥有任何资源,无论是托管的还是托管的。

    那么你就不需要 IDisposable 模式了。

    这个方法 [ThrowIfDisposed()] 然后在每个“真正”工作的方法开始时被调用。

    这里的问题是:为什么?

    如果您确实想跟踪可用/废弃状态,那么不要将其称为 IsDisposed。

    为什么(库)类 Controller 不实现 ThrowIfDisposed() 或类似的东西?

    因为没用。

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

    【讨论】:

    • 我完全同意 Henk 的观点,这里不需要 IDisposable。
    • 这没有回答问题。分歧在于投掷或不投掷ObjectDisposedException。不是他们是否应该实施IDisposable
    【解决方案2】:

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

    至于IsDisposed,在大多数情况下我真的看不出它有多大用处。不知道对象是否被释放的代码通常不会对对象的状态有足够的了解,无法知道它是否可能由于其他原因而无法使用;因此,不知道一个对象是否被释放的代码通常不应该对它做任何事情,除非——在某些情况下——给Dispose它,并且在大多数情况下,人们想调用Dispose如果对象尚未被处理,则应简单地无条件调用Dispose。拥有一个 MayNeedDisposing 方法可能会有一些价值,它会为具有非平凡 Dispose 方法的对象返回 true,直到它们被处置,但是这样的方法可以无条件地返回 false 对于具有 null @ 的对象987654332@方法[在一个类的情况下,例如注册一个回调纯粹是为了在某事上调用Dispose,事先测试MayNeedDisposing可能是一个有用的优化]。

    最后,关于一个类或接口是否应该实现或继承IDisposable,问题不在于类型本身是否获取资​​源,而是对获取资源的东西的最后幸存引用是否可能存储在该类型中类型。例如,尽管绝大多数 IEnumerator<T> 实现不获取资源,但有些实现,并且在许多此类情况下,对此类对象的唯一引用将存储在类型为 IEnumerator<T> 的变量中,由没有知道有问题的对象是否有任何资源。请注意,非泛型IEnumerator 没有实现IDisposable,但某些实现会获取资源。因此,调用IEnumerable.GetEnumerator 的代码如果实现IDisposable,则需要在返回的枚举数上调用DisposeIEnumerator 不继承 IDisposable 的事实并不能免除接收 IEnumerator 实现的代码,该实现也实现 IDisposable 的责任是调用 Dispose——它只会使此类代码更难履行这一职责。

    【讨论】:

      【解决方案3】:

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

      以所描述的方式和给出的原因实施 IDisposable 违反了至少三个良好原则。

      1. 你不需要它。 http://c2.com/cgi/wiki?YouArentGonnaNeedIt
      2. 尽可能做最简单的事情。 http://www.xprogramming.com/Practices/PracSimplest.html
      3. 保持简单愚蠢。 https://en.wikipedia.org/wiki/KISS_principle

      在每个层面上都是错误的。不要这样做。

      【讨论】:

        猜你喜欢
        • 2020-08-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-26
        • 1970-01-01
        • 1970-01-01
        • 2017-03-14
        相关资源
        最近更新 更多