【问题标题】:When is it reasonable to check if this object has been disposed and throw ObjectDisposedException?何时检查此对象是否已被释放并抛出 ObjectDisposedException 是否合理?
【发布时间】:2011-05-27 09:38:06
【问题描述】:

在实现IDisposable 的类中,何时检查对象是否已被释放并抛出ObjectDisposedException 是否合理?在所有公共方法和属性中(Dispose 除外)?有时?从来没有?

【问题讨论】:

  • 你不会简单地将对象包装在 using 语句中吗?因此在不需要时自动处理对象?
  • @Darren:那么您假设我的一次性类型的 user 行为正确。很少这样! :-)
  • @Lazarus:GC 与IDisposable/Dispose 没有任何关系。 GC 收集未引用的对象;它不会处理任何东西。
  • 好的不错的一个.. 所以如果 dispose 出现任何问题,那么您将如何知道对象是否已被释放,这正是您要寻找的吗?
  • @Lazarus:我认为您误解了 dispose 的含义。 Dispose 只不过是类实现的接口中的一个方法。它真的与 GC 或 CLR 无关。

标签: c# dispose idisposable objectdisposedexception


【解决方案1】:

您应该只在对已处置对象不起作用的方法中实现该检查。

例如:
如果您的类关闭了Dispose 中的数据库连接或文件句柄,则所有需要这些数据库连接或文件句柄的方法都需要检查该实例是否已公开。

【讨论】:

    【解决方案2】:

    如果对象支持 IsDisposed,则该方法本身不应该抛出;如果 IsDisposed 返回 true,则许多其他方法都应该抛出异常,但异常应该由这些方法生成,而不是由 IsDisposed 生成。一个人可能有一个实用方法 AssertNotDisposed,如果一个对象被释放,它会抛出,但这种行为应该来自具有该名称的方法。

    否则,我建议在很多情况下,让一个对象持有 IDisposable 对象,并能够在保持有用状态的同时释放内部对象。例如,一个对象的功能是显示和维护一个无模式对话框以从用户那里获取信息,即使在对话框关闭后,它也可能有用地保留字段内容的副本。这样的对象应该提供一个“关闭”方法,该方法将处理内部的 Disposable 对象但保持有用的状态。虽然它也可以有一个 Dispose 方法,该方法会调用 Close,但也会设置一个“NoLongerValid”标志,该标志会导致字段属性抛出,但我认为这不会真正增加任何价值。

    我承认,很多情况下,一个对象在被释放后仍能保持有用状态,这表明一个类可能应该被拆分。例如,Font 类可能应该被拆分为一个非一次性 FontInfo 类(保存字体的描述,但不包含 GDI 句柄)和一个 IDisposable ReadyFont 类(继承 FontInfo,并封装 GDI 字体对象)。使用字体的例程可以检查给定的对象是 FontInfo 还是 ReadyFont;在前一种情况下,他们可以创建 GDI 字体,使用它,然后发布它;在后一种情况下,他们可以使用 ReadyFont 的 GDI 字体对象并释放它。 ReadyFont 的创建者将负责确保其清理。

    事实上,我不知道系统在渲染控件时是否会尝试使用与控件的 Font 属性关联的 GDI 对象,但我知道如果 Font 被 Disposed(即使它在将其分配给 Font 属性之前已处置!)。如果需要,控件当然可以创建新的 GDI 字体;我不知道他们是否总是创建一种新的 GDI 字体,或者他们是否只在旧字体被处理后才这样做。前一种行为似乎性能更高,但除非仔细编码,否则如果一个线程尝试在另一个线程使用字体时释放字体,则可能会导致问题。

    【讨论】:

      【解决方案3】:

      唯一真正指定的是public void Dispose() 本身应该抛出任何东西。

      并且任何需要(非)托管资源的方法都应该抛出。

      在我看来,只有几个有争议的案例:

      • IsOpen、IsDisposed:我不会扔
      • 其他 IsSomeStatus:视情况而定。
      • 长度、计数、位置:我认为封闭的 Stream 没有长度,所以抛出

      当类组合(不相关的)函数(如 Stream 集合)时,会变得更加困难。我们只是不应该那样做。

      【讨论】:

        【解决方案4】:

        使用已处置的对象是您希望尽快找到的编程错误。

        检查的地方越多,发现错误的速度就越快。
        您绝对应该检查它在哪里处置的对象会导致某种其他类型的异常(即空指针)不会让用户感到困惑。

        在其他地方,是否值得努力取决于应用程序。

        【讨论】:

          【解决方案5】:

          正如您所说,我将在除 Dispose 和 IsDisposed 之外的所有公共方法和属性中实现此检查。这是standard pattern,以防止开发人员误以为它仍然有效而使用您的类型。

          【讨论】:

          • 有一定的酌处权。 IsDisposed 和/或 IsOpen 成员呢?
          • 我会选择 IsOpen。对于 IsDisposed,我不会扔。
          猜你喜欢
          • 2011-11-16
          • 1970-01-01
          • 2023-03-11
          • 1970-01-01
          • 1970-01-01
          • 2013-08-20
          • 1970-01-01
          • 2011-02-07
          • 2017-02-16
          相关资源
          最近更新 更多