【问题标题】:When do I need to manage managed resources?我什么时候需要管理托管资源?
【发布时间】:2009-09-15 07:54:15
【问题描述】:

我一直在研究标准的 Dispose 模式,我只是想知道我需要写什么来释放托管资源?如果这些资源已经被“管理”,那么我肯定不需要做任何事情。

如果是这种情况,并且我的类不包含任何非托管资源(因此不需要由 GC 完成),那么我是否只需要在我的 Dispose 方法中禁止完成? :-

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

所以假设这是我的班级:

public sealed class MyClass : IDisposable
{
    IList<MyObject> objects; // MyObject doesn't hold any unmanaged resource
    private bool _disposed;

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

    private void Dispose(bool disposing)
    {
        if (!_disposed)
        {  
            // do I need to set the list to null and 
            // call Dispose on each item in the list?
            if (disposing)
            {
                foreach (var o in objects)
                    o.Dispose();

                objects = null;
            }
        }

        _disposed = true;
    }

    ~MyClass()
    {
        Dispose(false);
    }
}

我真的需要在这里释放托管资源吗?

谢谢,

【问题讨论】:

    标签: c# design-patterns dispose


    【解决方案1】:

    如果您的类包含任何 IDisposable 实例,则您正在使用托管资源,因此您应该实现 IDisposable 以允许用户处置资源。您的 Dispose 方法应在托管资源上调用 Dispose

    至于释放托管内存,您无需执行任何操作。这是由 GC 处理的,但这是由 GC 处理的清理的唯一部分。托管和非托管资源必须由Dispose 和/或终结器清理。

    如果您不使用任何托管或非托管资源,则无需实现 IDisposable 或终结器。实现终结器实际上会影响你的类型的性能,所以除非你需要它,否则不要实现它。

    【讨论】:

    • 感谢 Brian,即使我的类不使用任何托管或非托管资源,实现 IDisposable 接口并在 Dispose 实现中调用 SuppressFinalize(this) 以阻止 GC 尝试完成实例?
    • 如果您没有任何需要清理的东西,那么实施 IDisposable 有什么好处?我知道 IDisposable 有时用于实现进入/退出上下文构造,但 IMO 这只会增加围绕使用 IDisposable/终结器的明显混乱。
    • @theburningmonk:除非您明确实现了终结器,否则 GC 不会尝试终结您的对象。所以不,你不需要为了调用SuppressFinalize而实现IDisposable
    【解决方案2】:

    您应该处置任何实现IDisposable 的托管对象。

    您将无法在未实现 IDisposable 的对象上调用 Dispose,因此您需要进行检查。 (显然,如果MyObject 的所有可能实例/后代都将始终实现IDisposable,那么您将不需要该检查。)

    无需将列表本身设置为null

    在一般情况下,我可能会重新编写循环,使其看起来像这样:

    if (disposing)
    {
        foreach (var o in objects)
        {
            var d = o as IDisposable;
            if (d != null) d.Dispose();
        }
    }
    

    (顺便说一句,如果您的类实际上不包含任何 IDisposable 对象或非托管资源,那么您可能根本不需要实现 IDisposable 或终结器。)

    【讨论】:

      【解决方案3】:

      实施 IDisposable 有两个原因:
      1. 释放联合国管理的资源。这种情况非常罕见-但不幸的是,很多文档都在谈论它。 这是关于释放什么 - 即避免泄露资源/内存。
      2.释放托管资源。这很常见 - 这不是关于确保释放什么(因为托管资源总是会在某个时候被 GC 释放),而是关于何时释放东西。即它让对象的用户控制它何时释放托管资源(即当它关闭套接字或文件等时),以便其他东西可以得到它们。

      在您的情况下,如果没有派生类添加托管资源,您可以使用以下minimum dispose

      public virtual void Dispose() {
          foreach (var o in objects) {
              var d = o as IDisposable;
              if (d != null) d.Dispose();
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2013-02-02
        • 1970-01-01
        • 2011-03-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多