我应该在包含数据集的类中添加析构函数/终结器吗?

时间:2012-05-04 14:00:18

标签: c# destructor dispose idisposable

我已阅读有关disposing of datasets的帖子,我仍然对析构函数有疑问。我知道帖子基本上说你不需要处理数据集,数据表和数据视图,但我的数据集是大量的,所以我想尽快释放那个内存。所以,我的问题是,我是否应该包含一个析构函数,即使在调用我的对象的dispose方法时将处理数据集?另外,再次向我解释为什么需要“bool处理”。

        public DEditUtil(DataSet dsTxData)
    {
        this.dsTxData = dsTxData;
    }

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

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
                dsTxData.Dispose();

            disposed = true;
        }
    }

    ~DEditUtil()
    {
        Dispose(false);
    }

4 个答案:

答案 0 :(得分:4)

是的,一般情况下,只要满足以下任一条件,您就应该实施full IDisposable pattern

  1. 您的班级分配了非托管资源,或
  2. 您拥有实施IDisposable的托管资源(这意味着他们反过来拥有非托管资源)
  3. 终结器的存在(C ++ / C#称为“析构函数”的一般CLR术语)是处理由于某种原因未调用Dispose方法的情况。传递给受保护的Dispose()方法的布尔值表示您是在公共Dispose内还是在终结器内进行调用。

    如果调用了公共Dispose方法,则该调用堆栈是确定性的:您的dispose方法是直接调用的,因此您可以安全地调用子对象上的方法(包括Dispose)。 / p>

    如果您在终结器内,那么您不知道其他对象也在进行垃圾收集。通常,在终结器中调用托管对象上的方法可能不安全。

    因此,布尔值基本上表示:“如果为true,则处置所有内容;如果为false,则仅处置我的非托管资源,并让其他人处理他们的内容。”

答案 1 :(得分:2)

一旦代码不再引用,DataSet对象使用的内存将可用于垃圾回收。

垃圾收集器将在稍后(非确定)时间将该内存提供给程序。

这两件事都不依赖于是否有析构函数或调用Dispose,所以答案是否定的 - 你不需要析构函数。

答案 2 :(得分:1)

不,你这里不需要任何其他方法调用,这已经足够你所做的了。 Dispose将由运行时调用,您将释放资源,清理让我们决定如何以及何时执行此操作。

如果您有真的内存存在巨大问题,您可以尝试到cal GC.Collect()来强制收集垃圾,这通常有效,但它永远不会以这种方式使用它的好习惯,所以尽量避免使用它。

编辑

根据评论,重要的是要注意你的案例中的执行流程,因为DataSet清理只会 ,如果它不是{来自代码的{1}}和disposed==false仅在代码的远程调用期间才会出现。

答案 3 :(得分:1)

用户编写的类很少使用终结器(或C#析构函数)用于除了记录调用Dispose失败之外的任何目的。除非深入研究终结器如何工作的细节,并确切地保证它们运行的​​上下文有什么保证,否则不应该在终结器中调用任何其他对象的Dispose方法。特别是,如果某个对象的Finalize()方法正在运行,那么它拥有引用的任何IDisposable对象通常都属于以下类别之一:

  1. 其他人仍然有对该对象的引用并期望它可用,因此调用`Dispose`会很糟糕。
  2. 无法在终结器线程上下文中安全地处理对象,因此调用`Dispose`会很糟糕。
  3. 如果对于'Dispose`处理程序有任何有意义的事情,该对象将使当前对象保持活动状态;当前对象的`Finalize`方法正在运行这一事实意味着不再需要在另一个对象上调用`Dispose`(这种情况可能发生在事件中)。
  4. 该对象已经调用了它的`Finalize`方法,因此调用`Dispose`最多是多余的。
  5. 该对象被调度为调用了`Finalize`方法,因此调用`Dispose`可能是多余的。

虽然在某些情况下某个对象可能需要在IDisposable方法中清理另一个Finalize对象,但在这种情况下正确使用Finalize会很棘手,并且使用它不正确比根本不使用它更糟糕。除其他事项外,Finalize通常仅在实体请求IDisposable时运行,并且在放弃之前错误地无法调用Dispose。通常最好将一个人的努力集中在确保Dispose在放弃对象之前正确获取,而不是试图正确处理有缺陷的消费者代码。