DataSet和DataTable都实现了IDisposable,因此,通过传统的最佳实践,我应该调用它们的Dispose()方法 .
但是,从我到目前为止所读到的,DataSet和DataTable实际上并没有任何非托管资源,因此Dispose()实际上并没有做太多 .
另外,我不能只使用 using(DataSet myDataSet...)
,因为DataSet有一组DataTables .
所以,为了安全起见,我需要遍历myDataSet.Tables,处理每个DataTables,然后处理DataSet .
那么,在我的所有DataSet和DataTable上调用Dispose()是否值得麻烦?
Addendum:
对于那些认为应该处理DataSet的人:通常,处理的模式是使用 using
或 try..finally
,因为您要保证将调用Dispose() .
然而,这对于一个集合来说真的很快 . 例如,如果对Dispose()的一个调用抛出异常,你会怎么做?你吞下它(这是“坏”),以便你可以继续处理下一个元素?
或者,你是否建议我只调用myDataSet.Dispose(),而忘记在myDataSet.Tables中处理DataTables?
11 回答
我会在对象实现IDisposeable时调用dispose . 这是有原因的 .
DataSet可能是巨大的内存生长 . 他们越早被标记为清理就越好 .
update
我回答这个问题已经5年了 . 我仍然同意我的回答 . 如果存在dispose方法,则在完成对象时应调用它 . IDispose接口的实现是有原因的 .
即使对象没有非托管资源,处置也可能通过破坏对象图来帮助GC . 通常,如果object实现了IDisposable,则应调用Dispose() .
Dispose()实际上是否做某事取决于给定的类 . 在DataSet的情况下,Dispose()实现继承自MarshalByValueComponent . 它从容器中删除自己并调用Disposed事件 . 源代码如下(用.NET Reflector反汇编):
数据集实现了IDisposable彻底的MarshalByValueComponent,它实现了IDisposable . 由于管理数据集,因此调用dispose没有任何实际好处 .
你自己创建DataTables吗?因为通常不需要遍历任何Object的子节点(如在DataSet.Tables中),因为它是Parent的工作来处置它的所有子成员 .
通常,规则是:如果您创建了它并且它实现了IDisposable,请将其公开 . 如果你没有创建它,那么不要处置它,这是父对象的工作 . 但是每个对象可能都有特殊规则,请查看文档 .
对于.net 3.5,它明确地说“不再使用时处理它”,这就是我要做的 .
首先,我将检查Dispose对DataSet的作用 . 也许使用redgate的反射器会有所帮助 .
以下是一些讨论,解释了为什么Dispose不是DataSet所必需的 .
To Dispose or Not to Dispose ?:
Should Dispose be called on DataTable and DataSet objects?包括MVP的一些解释:
Understanding the Dispose method and datasets?与当局Scott Allen发表评论:
所以,有共识的是 there is currently no good reason to call Dispose on a DataSet.
您应该假设它执行了一些有用的操作并调用Dispose,即使它当前没有任何操作 . NET Framework的版本,不能保证它将在未来的版本中保持这种方式导致资源使用效率低下 .
Update (December 1, 2009):
我想修改这个答案,并承认原来的答案是有缺陷的 .
原始分析 does 适用于需要最终确定的对象 - 并且如果没有准确,深入的理解,表面上不应接受的做法仍然存在 .
然而,事实证明,DataSets,DataViews,DataTables suppress finalization in their constructors - 这就是为什么在它们上面调用Dispose()显然什么都不做 .
据推测,这是因为他们没有非托管资源;因此,尽管 MarshalByValueComponent 允许非托管资源,但这些特定实现并不需要,因此可以放弃最终确定 .
(.NET作者会注意抑制通常占用最多内存的类型的最终化,这说明了这种实践对于可终结类型的重要性 . )
尽管如此,自.NET Framework(大约8年前)开始以来,这些细节仍未得到充分记录 . 非常令人惊讶的是(你基本上只能依靠自己的设备来筛选,但是将这些碎片放在一起的冲突,模糊的材料有时令人沮丧,但确实提供了对我们日常依赖的框架的更完整的理解) .
经过大量阅读,这是我的理解:
如果一个对象需要最终化,那么 could 占用的内存比它需要的时间长 - 这就是原因:a)任何定义析构函数的类型(或者从定义析构函数的类型继承)都被认为是可终结的; b)在分配时(在构造函数运行之前),指针放在Finalization队列上; c)可终结物体通常需要回收 2 collections (而不是标准1); d)禁止终结不会从终结队列中删除对象(由SOS中的!FinalizeQueue报告)此命令具有误导性;知道最终化队列中的对象(在其本身中)是没有用的;知道最终化队列中的对象并且仍然需要最终确定将是有帮助的(是否有一个命令?)
抑制终结会在对象的标头中稍稍关闭,向运行时指示它不需要调用其Finalizer(不需要移动FReachable队列);它保留在Finalization队列中(并继续由SOS中的!FinalizeQueue报告)
DataTable,DataSet,DataView类都以MarshalByValueComponent为根,MarshalByValueComponent是一个可以(可能)处理非托管资源的可终结对象
因为DataTable,DataSet,DataView不引入非托管资源,所以它们在构造函数中抑制了最终化
虽然这是一种不寻常的模式,但它使调用者不必担心在使用后调用Dispose
这可能是DataTables可能在不同的DataSet之间共享的事实,这可能是DataSets不关心处理子DataTables的原因 .
这也意味着这些对象将出现在SOS中的!FinalizeQueue下
However, these objects should still be reclaimable after a single collection, like their non-finalizable counterparts
4 (new references):
http://www.devnewsgroups.net/dotnetframework/t19821-finalize-queue-windbg-sos.aspx
http://blogs.msdn.com/tom/archive/2008/04/28/asp-net-tips-looking-at-the-finalization-queue.aspx
http://issuu.com/arifaat/docs/asp_net_3.5unleashed
http://msdn.microsoft.com/en-us/magazine/bb985013.aspx
http://blogs.msdn.com/tess/archive/2006/03/27/561715.aspx
Original Answer:
在这方面有很多误导性和一般性很差的答案 - 任何落在这里的人都应该忽略噪音并仔细阅读下面的参考文献 .
毫无疑问,Dispose should be 调用任何Finalizable对象 .
DataTables are Finalizable .
调用Dispose significantly 可加快回收内存的速度 .
MarshalByValueComponent 在其Dispose()中调用 GC.SuppressFinalize(this) - 跳过这意味着在回收内存之前必须等待数十个(如果不是数百个)Gen0集合:
从Gen2中看到100多个未引用的DataTables MB的人那里得到它:这非常重要,完全错过了这个帖子的答案 .
References:
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/
如果您的意图或此问题的上下文实际上是垃圾收集,那么您可以将数据集和数据表明确设置为null或使用关键字using并让它们超出范围 . 尽管Tetraneutron早些时候说过,但处理并不多 . GC将收集不再引用的数据集对象以及超出范围的数据集对象 .
我真的希望在强制要求回答之前,强迫人们投票实际写评论 .
尝试使用Clear()函数 . 这对我来说非常适合处置 .