C# 应该";处置;是否仅用于包含非托管资源的类型?
我最近与一位同事讨论了C# 应该";处置;是否仅用于包含非托管资源的类型?,c#,garbage-collection,idisposable,finalizer,finalization,C#,Garbage Collection,Idisposable,Finalizer,Finalization,我最近与一位同事讨论了Dispose的价值以及实现IDisposable的类型 我认为对应该尽快清理的类型实施IDisposable,是有价值的,即使没有非托管资源要清理 我的同事有不同的想法;如果没有任何非托管资源,则无需实现IDisposable,因为您的类型最终将被垃圾收集 我的观点是,如果您有一个希望尽快关闭的ADO.NET连接,那么实现IDisposable和使用新的MythingWithConnection()是有意义的。我的同事回答说,实际上,ADO.NET连接是一种非托管资源。我
Dispose
的价值以及实现IDisposable
的类型
我认为对应该尽快清理的类型实施IDisposable
,是有价值的,即使没有非托管资源要清理
我的同事有不同的想法;如果没有任何非托管资源,则无需实现IDisposable
,因为您的类型最终将被垃圾收集
我的观点是,如果您有一个希望尽快关闭的ADO.NET连接,那么实现IDisposable
和使用新的MythingWithConnection()
是有意义的。我的同事回答说,实际上,ADO.NET连接是一种非托管资源。我对他的回答的回答是,一切最终都是非托管资源
我知道如果调用了Dispose
,您将释放托管和非托管资源,但是如果通过finalizer/destructor调用,则只有释放非托管资源(不久前还写了关于如何释放的博客)
所以,我的问题是,如果您的类型不包含非托管资源,那么是否值得实现
IDisposable
?IDisposable有不同的有效用途。一个简单的例子是保存一个打开的文件,当您不再需要它时,需要在某个时刻将其关闭。当然,您可以提供一个方法Close
,但是将它放在Dispose
中,并使用类似的模式使用(var f=new MyFile(path)){/*process it*/}
将更加安全
一个更流行的例子是保存一些其他的IDisposable
资源,这通常意味着您需要提供自己的Dispose
,以便也处理它们
通常,只要您想要对任何东西进行确定性销毁,就需要实现IDisposable
我的观点和你的不同之处在于,只要某些资源需要确定性销毁/释放,我就实施IDisposable
,而不是尽快实施。在这种情况下,依赖垃圾收集不是一种选择(与您同事的说法相反),因为它发生在不可预测的时刻,实际上可能根本不会发生
事实上,任何资源都是不受保护的,这并不意味着什么:开发人员应该考虑“何时以及如何正确地处置这个对象”,而不是“它在保护下是如何工作的”。无论如何,底层实现可能会随时间而变化
实际上,C和C++之间的主要区别之一是缺省确定性破坏的缺失。小补充:释放资源和尽快释放资源之间的区别是什么?实际上,这些是不同的(尽管不是完全正交的)概念 如果要确定地释放资源,这意味着客户机代码应该可以说“现在,我希望释放此资源”。实际上,这可能不是释放资源的最早时刻:持有资源的对象可能已经从资源中获得了它所需要的一切,因此它可能已经释放了资源。另一方面,即使在对象的
Dispose
运行之后,对象也可能选择保留(通常是非托管的)资源,仅在finalizer中清理它(如果长时间保留资源不会产生任何问题)
因此,为了尽快释放资源,严格来说,Dispose
是不必要的:只要对象意识到不再需要资源,它就可以释放资源<但是,code>Dispose提供了一个有用的提示,表明不再需要对象本身,因此如果合适的话,可能会在此时释放资源
还有一个必要的补充:需要确定性释放的不仅仅是非托管资源!这似乎是这个问题的答案之间意见分歧的关键点之一。一个人可以有纯粹的想象结构,这可能需要被确定性地释放 例如:访问某个共享结构的权限(想想看)、巨大的内存块(假设您正在手动管理该程序的部分内存)、使用其他程序的许可证(假设您不允许同时运行某个程序的X个以上副本),在这里,要释放的对象不是非托管资源,而是执行/使用某些操作的权利,这是程序逻辑的纯粹内部构造
小添加:这里是一个小列表,列出了[ab]使用
IDisposable
:。不,它不是仅用于非托管资源
建议使用框架调用的基本清理内置机制,使您能够清理所需的任何资源,但最合适的是自然的非托管资源管理。如果您聚合了
IDisposable
s,那么您应该实现该接口,以便及时清理这些成员。在您引用的ADO.Net连接示例中,myConn.Dispose()
但是,我认为,在这种情况下,说一切都是非托管资源是不正确的。我也不同意你同事的看法
internal class Class1 : IDisposable
{
public Class1()
{
Console.WriteLine("Construct");
}
public void Dispose()
{
Console.WriteLine("Dispose");
}
~Class1()
{
Console.WriteLine("Destruct");
}
}
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
Class1 obj = new Class1();
obj.Dispose();
}
Console.ReadKey();
}
using (WindowsImpersonationContext context = SomeUserIdentity.Impersonate()))
{
// do something as SomeUser
}
// back to your user
Cursor savedCursor = Cursor.Current;
try {
Cursor.Current = Cursors.WaitCursor;
SomeLongOperation();
}
finally {
Cursor.Current = savedCursor;
}
using (new WaitCursor()) {
SomeLongOperation();
}
public sealed class WaitCursor: IDisposable {
private Cursor m_Saved;
public Boolean Disposed {
get;
private set;
}
public WaitCursor() {
Cursor m_Saved = Cursor.Current;
Cursor.Current = Cursors.WaitCursor;
}
public void Dispose() {
if (!Disposed) {
Disposed = true;
Cursor.Current = m_Saved;
}
}
}
using (new WaitCursor()) {
using (new RegisterServerLongOperation("My Long DB Operation")) {
SomeLongRdbmsOperation();
}
SomeLongOperation();
}