DataSet 和 DataTable 都实现了 IDisposable,因此,根据传统的最佳实践,我应该调用它们的 Dispose() 方法。

然而,从我到目前为止所读到的内容来看,DataSet 和 DataTable 实际上没有任何非托管资源,因此 Dispose() 实际上并没有做太多事情。

另外,我不能只使用 using(DataSet myDataSet...) 因为DataSet有DataTable的集合。

因此,为了安全起见,我需要遍历 myDataSet.Tables,处理每个 DataTable,然后处理 DataSet。

那么,是否值得在我的所有数据集和数据表上调用 Dispose() 呢?

附录:

对于那些认为应该处置 DataSet 的人:一般来说,处理的模式是使用 using 或者 try..finally, ,因为你想保证 Dispose() 会被调用。

然而,对于一个集合来说,这很快就会变得丑陋。例如,如果对 Dispose() 的调用之一引发异常,您该怎么办?你会吞下它(这是“坏的”)以便你可以继续处理下一个元素吗?

或者,您是否建议我只调用 myDataSet.Dispose(),而忘记在 myDataSet.Tables 中处理 DataTables?

有帮助吗?

解决方案

以下是一些讨论,解释了为什么 DataSet 不需要 Dispose。

处置还是不处置?:

DataSet 中的 Dispose 方法的存在只是因为继承的副作用——换句话说,它实际上在终结过程中没有做任何有用的事情。

是否应该对 DataTable 和 DataSet 对象调用 Dispose? 包括 MVP 的一些解释:

System.DATA名称空间(ADONET)不包含非管理资源。因此,只要您没有给自己添加一些特别的东西,就无需处理任何一个。

了解 Dispose 方法和数据集? 来自权威 Scott Allen 的评论:

在实践中,我们很少处理数据集,因为它几乎没有什么好处”

所以,大家的共识是 目前没有充分的理由对数据集调用 Dispose。

其他提示

更新(2009 年 12 月 1 日):

我想修改这个答案并承认原来的答案有缺陷。

原来的分析 适用于需要最终确定的对象——并且在没有准确、深入理解的情况下不应接受表面实践的观点仍然成立。

然而,事实证明,DataSet、DataView、DataTable 抑制构造函数中的终结 – 这就是为什么对它们显式调用 Dispose() 不会执行任何操作。

据推测,发生这种情况是因为他们没有非托管资源;所以尽管事实上 按值组件编组 考虑到非托管资源,这些特定的实现没有必要,因此可以放弃最终确定。

(.NET 作者会注意抑制通常占用最多内存的类型的终结,这说明了这种做法对于可终结类型的重要性。)

尽管如此,自 .NET Framework 诞生(大约 8 年前)以来,这些细节仍然没有得到充分记录,这非常令人惊讶(您基本上需要依靠自己的设备来筛选相互冲突、模棱两可的材料,以将各个部分组合在一起有时令人沮丧,但确实提供了对我们日常依赖的框架的更完整的理解)。

经过大量阅读,我的理解如下:

如果一个对象需要终结,它 可以 占用内存的时间超过其需要的时间——原因如下:a) 任何定义析构函数的类型(或从定义析构函数的类型继承)都被认为是可终结的;b) 在分配时(在构造函数运行之前),一个指针被放置在 Finalization 队列上;c) 可终结的对象通常需要 2 个收藏 被回收(代替标准1);d)抑制最终确定不会从最终确定队列中删除对象(如SOS中的finalizequeue报道)该命令具有误导性;知道终结队列上有哪些对象(就其本身而言)并没有什么帮助;了解终结队列上有哪些对象并且仍然需要终结会很有帮助(是否有一个命令?)

抑制终结会在对象的标头中关闭一点,向运行时指示它不需要调用其终结器(不需要移动 FReachable 队列);它保留在 Finalization 队列中(并继续由 SOS 中的 !FinalizeQueue 报告)

DataTable、DataSet、DataView 类都以 MarshalByValueComponent 为根,这是一个可终结的对象,可以(可能)处理非托管资源

  • 由于 DataTable、DataSet、DataView 不会引入非托管资源,因此它们会抑制构造函数中的终结
  • 虽然这是一种不寻常的模式,但它使调用者不必担心在使用后调用 Dispose
  • 这以及 DataTable 可能在不同 DataSet 之间共享的事实很可能是 DataSet 不关心处理子 DataTable 的原因
  • 这也意味着这些对象将会出现在SOS中的!FinalizeQueue下面
  • 然而,这些对象在一次收集之后仍然应该是可回收的,就像它们的不可终结的对应对象一样

4(新参考文献):

原答案:

关于这个问题有很多误导性的且通常非常糟糕的答案 - 任何来到这里的人都应该忽略噪音并仔细阅读下面的参考资料。

毫无疑问,处置 应该 调用任何可终结的对象。

数据表 可最终确定。

调用处理 显著地 加速记忆的回收。

按值组件编组 来电 GC.SuppressFinalize(此) 在其 Dispose() 中 - 跳过这意味着在回收内存之前必须等待数十甚至数百个 Gen0 集合:

有了对最终确定的基本理解,我们已经可以推断出一些非常重要的事情:

首先,需要最终确定的对象比没有的对象更长。事实上,他们可以活得更久。例如,假设Gen2中的对象需要最终确定。最终确定将安排,但该对象仍在GEN2中,因此直到下一个Gen2集合发生之前,它才会被重新收集。这确实可能是很长时间了,实际上,如果事情进展顺利,那将是很长的时间,因为Gen2收集成本很高,因此我们希望它们很少发生。需要最终确定的较旧对象可能必须等待数十个GEN0收集,然后再收回其空间。

其次,需要最终确定的物体会导致附带损害。由于内部对象指针必须保持有效,因此不仅需要直接确定的对象在内存中持续存在,而且对象直接或间接地指的所有内容也将保留在内存中。如果一棵巨大的对象树是由一个需要终点的单个对象锚定的,那么整个树就可能会徘徊,可能会在我们刚刚讨论的情况下长时间持续。因此,很重要的是,很少使用最终化器,然后将它们放在具有尽可能少的内部对象指针的对象上。在我刚刚给出的树示例中,您可以通过将最终确定的资源移动到单独的对象并将其引用到树的根部中,从而轻松避免问题。随着这种适度的变化,只有一个对象(希望是一个不错的小物体)会持续,最终定性成本被降至最低。

最后,需要最终化的对象为最终器线程创建工作。如果您的最终确定过程是一个复杂的过程,那么唯一的终结器线程将花费大量时间执行这些步骤,这可能会导致工作积压,从而导致更多的对象等待最终确定。因此,最终化器要尽可能少的工作至关重要。还请记住,尽管所有对象指针在最终确定过程中均保持有效,但可能会导致这些指针导致已经完成的对象,因此可能毫无用处。通常,即使指针有效,避免在最终化代码中遵循对象指针,这是最安全的。安全,简短的定制代码路径是最好的。

这是从在 Gen2 中看到过数百 MB 的非引用数据表的人那里得到的:这非常重要,并且该线程的答案完全忽略了这一点。

参考:

1 - http://msdn.microsoft.com/en-us/library/ms973837.aspx

2 - http://vineetgupta.spaces.live.com/blog/cns!8DE4BDC896BEE1AD!1104.entry http://www.dotnetfunda.com/articles/article524-net-best-practice-no-2-improve-garbage-collector-performance-using-finalizedispose-pattern.aspx

3 - http://codeidol.com/csharp/net-framework/Inside-the-CLR/Automatic-Memory-Management/

您应该假设它确实有用的东西,并调用Dispose,即使它没有在当前。 .NET框架的化身,也不能保证它会保持这样在未来的版本中导致低效的资源使用。

即使对象没有任何非托管资源,处置可能有助于GC打破对象图。一般情况下,如果对象实现IDisposable然后处置()应被调用。

无论的Dispose()实际上做一些事情或不依赖于给定的类。在数据集的情况下,处置()实现从MarshalByValueComponent继承。它从容器中删除自身,并呼吁Disposed事件。源代码是下面(分解用.net反射):

protected virtual void Dispose(bool disposing)
{
    if (disposing)
    {
        lock (this)
        {
            if ((this.site != null) && (this.site.Container != null))
            {
                this.site.Container.Remove(this);
            }
            if (this.events != null)
            {
                EventHandler handler = (EventHandler) this.events[EventDisposed];
                if (handler != null)
                {
                    handler(this, EventArgs.Empty);
                }
            }
        }
    }
}

你自己创建的数据表?因为通过任何物体的孩子迭代(如DataSet.Tables)通常是不需要的,因为它是家长的工作,处理它的所有子成员。

一般情况下,规则是:如果你创建了它,它实现IDisposable,处置它。如果您没有创建它,然后不处理它,这是父对象的工作。但每个对象可具有特殊的规则,检查文档。

有关.NET 3.5,它明确地说,“不使用时,再处置它”,所以这就是我会做。

我调用dispose随时一个对象实现IDisposeable。这是有原因的。

数据集可以是巨大的存储器猪。越早它们可以被标记为用于清理,更好。

<强>更新

它已5年,因为我回答了这个问题。我还是同意我的答案。如果有一个Dispose方法,当你这个对象应该被调用。所述IDispose接口被实施的一个原因。

如果您有意或这个问题的背景是真正的垃圾收集,那么你可以设置数据集和数据表明确为空或使用使用关键字,让他们走出去的范围。作为Tetraneutron表示,早处置没有做太多。 GC将收集不再引用的数据集的对象,并且还那些超出范围。

我真的希望SO迫使人们反对投票downvoting答案之前,实际上写了评论。

数据集实现IDisposable彻底MarshalByValueComponent,这实现了IDisposable。由于数据集管理,没有实际的好处调用处理。

尝试使用清除()函数。 这对我的作品伟大的处置。

DataTable dt = GetDataSchema();
//populate dt, do whatever...
dt.Clear();
  

没有需要处理()     因为数据集继承MarshalByValueComponent类和MarshalByValueComponent实现IDisposable接口

首先,我会检查什么呢处置与一个DataSet。也许使用从展鹏反射器将有所帮助。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top