我什么时候需要管理托管资源?

时间:2009-09-15 07:54:16

标签: c# design-patterns dispose

我一直在看标准的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);
    }
}

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

谢谢,

3 个答案:

答案 0 :(得分:4)

如果您的班级拥有任何IDisposable个实例,那么您正在使用托管资源,因此您应该实施IDisposable以允许用户处置资源。您的Dispose方法应在托管资源上调用Dispose

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

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

答案 1 :(得分:3)

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

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

无需将列表本身设置为null

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

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

(顺便说一句,如果您的班级实际上没有任何IDisposable个对象或非托管资源,那么您可能根本不需要实施IDisposable或终结者。)< / p>

答案 2 :(得分:2)

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

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

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