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 and DataTable both implement IDisposable, so, by conventional best practices, I should call their Dispose() methods.
However, from what I've read so far, DataSet and DataTable don't actually have any unmanaged resources, so Dispose() doesn't actually do much.
Plus, I can't just use using(DataSet myDataSet...)
because DataSet has a collection of DataTables.
So, to be safe, I'd need to iterate through myDataSet.Tables, dispose of each of the DataTables, then dispose of the DataSet.
So, is it worth the hassle to call Dispose() on all of my DataSets and DataTables?
Addendum:
For those of you who think that DataSet should be disposed:
In general, the pattern for disposing is to use using
or try..finally
, because you want to guarantee that Dispose() will be called.
However, this gets ugly real fast for a collection. For example, what do you do if one of the calls to Dispose() thrown an exception? Do you swallow it (which is "bad") so that you can continue on to dispose the next element?
Or, do you suggest that I just call myDataSet.Dispose(), and forget about disposing the DataTables in myDataSet.Tables?
发布评论
评论(12)
以下是一些讨论,解释了为什么 DataSet 不需要 Dispose。
处置还是不处置?:
应该对 DataTable 和 DataSet 对象调用 Dispose 吗? 包括来自 MVP 的一些解释:
了解 Dispose 方法和数据集?有来自权威 Scott Allen 的评论:
因此,大家一致认为,目前没有充分的理由在 DataSet 上调用 Dispose。
Here are a couple of discussions explaining why Dispose is not necessary for a DataSet.
To Dispose or Not to Dispose ?:
Should Dispose be called on DataTable and DataSet objects? includes some explanation from an MVP:
Understanding the Dispose method and datasets? has a with comment from authority Scott Allen:
So, the consensus there is that there is currently no good reason to call Dispose on a DataSet.
更新(2009 年 12 月 1 日):
我想修改此答案并承认原始答案有缺陷。
最初的分析确实适用于需要最终确定的对象,并且在没有准确、深入理解的情况下不应接受表面实践的观点仍然成立。
然而,事实证明,DataSet、DataView、DataTable抑制其构造函数中的终结——这就是为什么对它们显式调用 Dispose() 不会执行任何操作。
据推测,发生这种情况是因为他们没有非托管资源;因此,尽管 MarshalByValueComponent 允许非托管资源,但这些特定的实现没有必要,因此可以放弃最终确定。
(.NET 作者会小心地抑制通常占用最多内存的类型的终结,这说明了这种做法对于可终结类型的重要性。)
尽管如此,自 .NET 诞生以来,这些细节仍然没有得到充分记录 。 .NET Framework(大约 8 年前)非常令人惊讶(您基本上需要依靠自己的设备来筛选相互冲突、模棱两可的材料,然后将各个部分组合在一起,这有时会令人沮丧,但确实提供了对我们每天依赖的框架)。
经过大量阅读后,我的理解是:
如果一个对象需要终结,它可能占用内存的时间比它需要的时间更长 - 原因如下:a) 定义析构函数的任何类型(或从定义析构函数的类型继承)被认为是可终结的; b) 在分配时(在构造函数运行之前),一个指针被放置在 Finalization 队列上; c) 可终结的对象通常需要回收2个集合(而不是标准的1个); d) 抑制终结不会从终结队列中删除对象(如 SOS 中的 !FinalizeQueue 所报告)
该命令具有误导性;知道终结队列上有哪些对象(就其本身而言)并没有什么帮助;知道哪些对象位于终结队列上并且仍然需要终结会很有帮助(是否有一个命令?)
抑制终结会在对象的标头中关闭一点,向运行时指示它不需要调用其终结器(不需要移动 FReachable 队列);它保留在 Finalization 队列中(并继续由 SOS 中的 !FinalizeQueue 报告)
DataTable、DataSet、DataView 类都以 MarshalByValueComponent 为根,这是一个可以(可能)处理非托管资源的可终结对象,
4(新引用):
原始答案:
有很多关于这个问题的误导性且通常非常糟糕的答案 - 任何来到这里的人都应该忽略噪音并仔细阅读下面的参考资料。
毫无疑问,应该对任何可终结的对象调用 Dispose。
数据表是可最终确定的。
调用 Dispose 显着加快内存回收速度。
MarshalByValueComponent 在其 Dispose() 中调用 GC.SuppressFinalize(this) - 跳过此操作意味着在回收内存之前必须等待数十个甚至数百个 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
<一个href="http://www.dotnetfunda.com/articles/article524-net-best-practice-no-2-improve-garbage-collector-performance-using-finalizedispose-pattern.aspx" rel="noreferrer">3 -
http://codeidol.com/csharp/net-框架/CLR内部/自动内存管理/
Update (December 1, 2009):
I'd like to amend this answer and concede that the original answer was flawed.
The original analysis does apply to objects that require finalization – and the point that practices shouldn’t be accepted on the surface without an accurate, in-depth understanding still stands.
However, it turns out that DataSets, DataViews, DataTables suppress finalization in their constructors – this is why calling Dispose() on them explicitly does nothing.
Presumably, this happens because they don’t have unmanaged resources; so despite the fact that MarshalByValueComponent makes allowances for unmanaged resources, these particular implementations don’t have the need and can therefore forgo finalization.
(That .NET authors would take care to suppress finalization on the very types that normally occupy the most memory speaks to the importance of this practice in general for finalizable types.)
Notwithstanding, that these details are still under-documented since the inception of the .NET Framework (almost 8 years ago) is pretty surprising (that you’re essentially left to your own devices to sift though conflicting, ambiguous material to put the pieces together is frustrating at times but does provide a more complete understanding of the framework we rely on everyday).
After lots of reading, here’s my understanding:
If an object requires finalization, it could occupy memory longer than it needs to – here’s why: a) Any type that defines a destructor (or inherits from a type that defines a destructor) is considered finalizable; b) On allocation (before the constructor runs), a pointer is placed on the Finalization queue; c) A finalizable object normally requires 2 collections to be reclaimed (instead of the standard 1); d) Suppressing finalization doesn’t remove an object from the finalization queue (as reported by !FinalizeQueue in SOS)
This command is misleading; Knowing what objects are on the finalization queue (in and of itself) isn’t helpful; Knowing what objects are on the finalization queue and still require finalization would be helpful (is there a command for this?)
Suppressing finalization turns a bit off in the object's header indicating to the runtime that it doesn’t need to have its Finalizer invoked (doesn’t need to move the FReachable queue); It remains on the Finalization queue (and continues to be reported by !FinalizeQueue in SOS)
The DataTable, DataSet, DataView classes are all rooted at MarshalByValueComponent, a finalizable object that can (potentially) handle unmanaged resources
4 (new references):
Original Answer:
There are a lot of misleading and generally very poor answers on this - anyone who's landed here should ignore the noise and read the references below carefully.
Without a doubt, Dispose should be called on any Finalizable objects.
DataTables are Finalizable.
Calling Dispose significantly speeds up the reclaiming of memory.
MarshalByValueComponent calls GC.SuppressFinalize(this) in its Dispose() - skipping this means having to wait for dozens if not hundreds of Gen0 collections before memory is reclaimed:
Take it from someone who's seen 100s of MBs of non-referenced DataTables in Gen2: this is hugely important and completely missed by the answers on this thread.
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/
您应该假设它做了一些有用的事情并调用 Dispose,即使它在当前的 .NET Framework 版本中什么也不做。无法保证它在未来版本中会保持这种状态,从而导致资源使用效率低下。
You should assume it does something useful and call Dispose even if it does nothing in current .NET Framework incarnations. There's no guarantee it will stay that way in future versions leading to inefficient resource usage.
即使对象没有非托管资源,处置也可能通过破坏对象图来帮助 GC。一般来说,如果一个对象实现了 IDisposable,就应该调用 Dispose()。
Dispose() 是否实际执行某些操作取决于给定的类。对于 DataSet,Dispose() 实现继承自 MarshalByValueComponent。它将自身从容器中删除并调用 Dispose 事件。源代码如下(用.NET Reflector反汇编):
Even if an object has no unmanaged resources, disposing might help GC by breaking object graphs. In general, if an object implements IDisposable, Dispose() should be called.
Whether Dispose() actually does something or not depends on the given class. In case of DataSet, Dispose() implementation is inherited from MarshalByValueComponent. It removes itself from container and calls Disposed event. The source code is below (disassembled with .NET Reflector):
您自己创建数据表吗?因为通常不需要迭代任何对象的子对象(如在 DataSet.Tables 中),因为父对象的工作是处理其所有子成员。
一般来说,规则是:如果您创建了它并且它实现了 IDisposable,则将其释放。如果您没有创建它,则不要处置它,这是父对象的工作。但每个对象可能有特殊的规则,请查看文档。
对于.NET 3.5,它明确表示“不再使用时将其丢弃”,所以这就是我要做的。
Do you create the DataTables yourself? Because iterating through the children of any Object (as in DataSet.Tables) is usually not needed, as it's the job of the Parent to dispose all its child members.
Generally, the rule is: If you created it and it implements IDisposable, Dispose it. If you did NOT create it, then do NOT dispose it, that's the job of the parent object. But each object may have special rules, check the Documentation.
For .NET 3.5, it explicitly says "Dispose it when not using anymore", so that's what I would do.
每当对象实现 IDisposeable 时,我都会调用 dispose。它的存在是有原因的。
数据集可能会占用大量内存。越早标记为清理越好。
更新
我回答这个问题已经五年了。我还是同意我的回答。如果有一个 dispose 方法,那么当你处理完该对象时应该调用它。实现 IDispose 接口是有原因的。
I call dispose anytime an object implements IDisposeable. It's there for a reason.
DataSets can be huge memory hogs. The sooner they can be marked for clean up, the better.
update
It's been 5 years since I answered this question. I still agree with my answer. If there is a dispose method, it should be called when you are done with the object. The IDispose interface was implemented for a reason.
如果您的意图或这个问题的上下文确实是垃圾收集,那么您可以显式将数据集和数据表设置为 null 或使用关键字 using 并让它们超出范围。 Dispose 并没有像 Tetraneutron 之前所说的那样起多大作用。 GC 将收集不再引用的数据集对象以及超出范围的数据集对象。
我真的希望迫使人们在对答案投反对票之前先写下评论。
If your intention or the context of this question is really garbage collection, then you can set the datasets and datatables to null explicitly or use the keyword using and let them go out of scope. Dispose does not do much as Tetraneutron said it earlier. GC will collect dataset objects that are no longer referenced and also those that are out of scope.
I really wish SO forced people down voting to actually write a comment before downvoting the answer.
数据集通过 MarshalByValueComponent 实现 IDisposable,MarshalByValueComponent 实现了 IDisposable。由于数据集是受管理的,因此调用 dispose 并没有真正的好处。
Datasets implement IDisposable thorough MarshalByValueComponent, which implements IDisposable. Since datasets are managed there is no real benefit to calling dispose.
尝试使用 Clear() 函数。
它对我来说非常适合处理。
Try to use Clear() function.
It works great for me for disposing.
这是正确处理
DataTable
的正确方法。This is the right way to properly Dispose the
DataTable
.这可能是处理和释放 DataSet 消耗的内存的最佳/正确方法。
And this can be the best/proper way to Dispose and release the memory consumed by
DataSet
.