代码之家  ›  专栏  ›  技术社区  ›  Nicolas Dorier

如果调用方忘记使用Dispose(),如何释放不会被垃圾收集的托管资源?

  •  2
  • Nicolas Dorier  · 技术社区  · 17 年前

    在我的代码中,我有一个创建新线程的类。这个新线程有一个调度程序,因此除非调用

    Dispatcher.CurrentDispatcher.InvokeShutdown();
    

    线程不能在我的类之外引用。 所以我在想:当我的对象被垃圾收集时,如何确保我的线程完成?

    一个响应是使用IDisposable,但如果有人忘记调用Dispose(),线程将永远不会停止,因此它不是解决方案。

    另一个响应是两次使用Dispose+Destructor,但我听说我们应该只在释放非托管资源时使用Destructor。我走到了死胡同。

    3 回复  |  直到 17 年前
        1
  •  2
  •   Jon Skeet    17 年前

    一种选择是仅对调试生成使用终结器。不要让它只是“很好地”关闭线程:让它非常显著地记录警告。这将有助于隔离忘记正确处理对象的位置。

    您的调度员通常会非常频繁地接收事件吗?如果它长时间没有收到任何事件,您是否可以让它至少记录一条警告?

    一个相当糟糕的选择是使调度器对一次性对象具有弱引用。它可以定期检查对象是否已被垃圾收集(使用 WeakReference.IsAlive )如果是的话,它会自动关闭。同样,这也不是非常令人愉快(应该记录一个警告)。

        2
  •  1
  •   VladV    17 年前

    “Dispose+Destructor”解决方案在我看来很好。正如Jon所说,您可以使用一些技巧来检测是否错过了Dispose调用,但是在终结器调用时停止线程将是一种额外的保护措施。

    顺便说一下,线程是非托管资源。

        3
  •  1
  •   IRBMe    17 年前

    here . 显然,如果您正在编写一个可重用类或库供其他程序员使用,您不能假设Dispose方法总是被调用,因此最好实现一个终结器:

    public void Dispose()  {
        Dispose(true);
        GC.SuppressFinalize(this); 
    }
    
    protected virtual void Dispose(bool disposing) {
        if (disposing) {
            // Free other state (managed objects).
        }
        // Free your own state (unmanaged objects).
        // Set large fields to null.
    }
    
    ~MyClass() {
        Dispose (false);
    }
    

    看来不是这样 那个

    • 如果出现以下情况,则在终结器中清理资源 Dispose 不叫
    • 同上,但也会记录警告或错误
    • 如果调用终结器,请大声失败

    您可以通过保护最后2个版本来防止它们被编译到版本中:

    ~MyClass() {
        Dispose (false);
        #if DEBUG
            // log a warning or scream at the developer in some way
        #endif
    }
    
    推荐文章