如何正确实现IDisposable

10 c# idisposable

在我作为开发人员的时候,我已经看到了很多C#代码,它试图通过将变量设置为null或者在类(例如DataSet)上调用Dispose()并在我自己的类Dispose()方法中帮助GC.一直在想是否需要在托管环境中实现它.

这个代码在设计模式中是浪费时间吗?

class MyClass : IDisposable 
{
    #region IDisposable Members

    public void Dispose() 
    {
        otherVariable = null;
        if (dataSet != null)
        {
            dataSet.Dispose();
        }
    }

    #endregion
}
Run Code Online (Sandbox Code Playgroud)

Cod*_*uth 11

GC 不会调用.Dispose()(但是,它会调用finalize ~MyClass()方法,您可以调用该Dispose()方法,以便在GC决定清理您的类时自动管理资源).

您必须始终提供一种处理内部资源的方法,例如DataSets使用您的类的代码(并确保您实际调用.Dispose()或包装构造函数using).使用IDisposable强烈建议您类使用内部资源.

来自MSDN:

此接口的主要用途是释放非托管资源.当不再使用该对象时,垃圾收集器会自动释放分配给托管对象的内存.但是,无法预测垃圾收集何时发生.此外,垃圾收集器不了解非托管资源,例如窗口句柄,或打开文件和流.

public void Dispose()
{
    otherVariable = null;
    if (dataSet != null)
    {
        dataSet.Dispose();
        dataSet = null;
    }
}
Run Code Online (Sandbox Code Playgroud)


Sim*_*ens 6

不,处理方法不是浪费时间.

配置模式允许调用者在完成后立即清理类,而不是等待GC收集它.对于普通堆内存,延迟并不重要,这就是为什么基本类String没有实现它.然而,Dispose有用的是清理非托管资源.在内部某处,Dataset类使用非托管资源,因此它提供了一种dispose方法,允许您在释放非托管资源时通知它.

如果正确地遵循了模式,Dataset也会有一个终结器(或者某个子类),这意味着如果你没有手动处理它,最终GC会运行,终结器将被调用,非托管资源将被清除就这样.此非托管资源可能是重要的,虽然,想象一下,如果它是一个文件锁,或者数据库连接,你真的不想流连等待GC运行之前,你可以重用的数据库连接.Dispose提供了一种确定性的方法,可以在资源完成时清理资源,而不是依赖于非确定性GC.

至于在dispose方法中将变量设置为null.几乎所有情况都是毫无意义的.将变量设置为null会删除对该变量的引用,这将使其符合垃圾收集的条件(如果这是最后一个引用),但是当您正在处理该类时,您可能会超出范围因此,无论如何内部类都将有资格收集.

如果您的类中有成员变量是您创建的一次性变量(不仅仅是您持有的引用),那么您应该始终从您自己的类的dispose方法调用dispose,但不要将它们设置为null.


Jam*_*ney 2

不是完全。如果您有可处置的成员变量,那么您可能应该像这样处置它。您的对象的生存时间可能比它正在执行的工作范围长,因为垃圾收集器不能保证在任何特定时间运行。

不过,将托管变量设置为 null 是浪费时间。该对象不会更快地被 GC 回收。