【问题标题】:Can you fire a "Disposing" event if Dispose() is called by a Finalizer?如果终结器调用 Dispose(),你能触发“Disposing”事件吗?
【发布时间】:2016-01-22 16:10:51
【问题描述】:

我注意到 MSDN (like this one) 上有一些课程有一个 Disposing 事件并带有以下评论:

在调用 Dispose 时或当垃圾收集器最终确定并收集此对象时发生。

我想在我的一个班级中实现我自己的Disposing 事件。这是我的基本实现(following the best practices for the dispose pattern):

public abstract class Handle : IDisposable
{
    public bool Disposed { get; private set; }

    public event System.Action DisposingCompleted;

    public Handle()
    {
        Disposed = false;
    }

    ~Handle()
    {
        Dispose(false);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing = false)
    {
        if (Disposed)
        {
            return;
        }

        if (disposing)
        {
            HandleManagedResources();
        }

        HandleUnManagedResources();

        Disposed = true;

        if (DisposingCompleted != null)
        {
            DisposingCompleted();
        }
    }

    protected virtual void HandleManagedResources() {}
    protected virtual void HandleUnManagedResources() {}
}

有人在我的代码审查中提到,他们不确定触发这样的事件是否安全,因为 Dispose() 可能会从终结器中调用,但是根据我在该 MSDN 链接上添加的 cmets顶部,很明显有对象在 Disposed OR Finalized 时触发事件。

是我遗漏了什么还是安全? GraphicsDevice 如何实现从 dispose 或最终确定时触发的事件?如果答案只是“不,你永远不能这样做”,那么还有其他方法可以达到同样的效果吗? (对象被释放的事件OR已完成)

【问题讨论】:

  • 您应该使用标准建议的实现和模式,例如命名和约定,而不是自己滚动。特别是,您应该使用bool disposing 而不是bool fromFinalizer
  • @LasseV.Karlsen 当然,我改了名字。
  • 您可能想阅读 Eric Lipperts 的帖子,了解终结器ericlippert.com/2015/05/18/… 中可能发生的所有怪异现象@
  • 从不,从不disposing 为 false 时引发事件。你不能让终结器运行任意代码,它不会导致问题的几率非常低。 Disposing 事件只有在你有足够的保证 Dispose() 方法将被调用时才是合理的。这往往很难实现。除非类对象完全在你的控制之下。
  • @HansPassant GraphicsDevice 如何实现一个事件,该事件可以在处置完成时触发?它由微软实现;我想如果它有问题会被注意到。

标签: c# events garbage-collection dispose idisposable


【解决方案1】:

如果您要在 Dispose 方法中执行任何涉及其他对象的操作,您应该只在显式调用 Dispose 时这样做,而不是在从终结器调用它时这样做。

这样做的原因是,如果其他对象也符合收集条件,则无法保证该对象尚未最终确定。

【讨论】:

  • 那么,我链接的GraphicsDevice 之类的事件是如何触发“当调用 Dispose 或完成此对象时”触发的?如果我能保证订阅者的寿命比发布者长呢?
  • 你可以很容易地写代码来做,但不推荐也不一定安全。
  • 所以我对微软制作的类如何实现它感到困惑。我很难相信 XNA 框架中内置的功能,如 GraphicsDeviceStorageContainer 能够做到这一点,但不要在任何地方指出这些事件使用起来不安全。如果答案只是“不,你永远不能这样做”,那么还有其他方法可以达到同样的效果吗?
  • 我没说你不能这样做。我说你不应该。你问一个普遍的问题,你会得到一个普遍的答案。如果您有特定的类,您可以以这样一种方式进行编程,即保证在最终对象上调用 Dispose 是安全的,那么就去做吧。 一般建议是不要这样做。
  • 如果你设法使终结线程崩溃,你的应用程序可能注定要失败。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-17
  • 1970-01-01
  • 2016-04-27
  • 2016-11-06
  • 2023-04-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多