探讨C#中Dispose方法与Close方法的区别详解
群里有人问,怎样直接清空堆里的string值。有人建议直接用dispose()方法;dispose()销毁了对象,是一种垃圾回收机制。(这里用using或许更好)
当我们开发c#代码的时候,经常碰到一个问题,有些class提供close(),有些class提供dispose(),那么dispose和close到底有什么区别?
在这里,要明确一下c#程序(或者说.net)中的资源。简单的说来,c#中的每一个类型都代表一种资源,而资源又分为两类:
托管资源:由clr管理分配和释放的资源,即由clr里new出来的对象;
非托管资源:不受clr管理的对象,windows内核对象,如文件、数据库连接、套接字、com对象等;毫无例外地,如果我们的类型使用到了非托管资源,或者需要显式释放的托管资源,那么,就需要让类型继承接口idisposable。这相当于是告诉调用者,该类型是需要显式释放资源的,你需要调用我的dispose方法。
首先,dispose和close基本上应该是一样的。close是为了那些不熟悉dispose的开发者设计的。因为基本上所有的developer都知道close是干吗的(特别是对于那些有c++背景的developer)。
但是当我们写code时候,如果要实现close和dispose的时候,要注意close和dispose的设计模式。.net的一些class只提供close,而且派生自idisposable,并且隐藏了dispose方法。是不是觉得很不明白了?
对这些class来说,关键在于它们显式的(explicitly)实现了idisposable。对于隐式实现来说,你只需要调用"newa().dispose()",但是对于显式实现来说,dispose不会是这个class的成员函数。唯一的调用方式是你先要cast到idisposable才行。(“new a().dispose()”编译不过,但是“((idisposable)newa()).dispose()”可以编译过)。所以这样就符合了设计的要求:提供close(),隐藏dispose(),并且实现了idisposable接口。
在.net的framework里,close()被设计成public的,并且在close()里面call被隐藏的dispose();dispose()去call另一个virtual的dispose(bool)函数。所以如果你从这个class继承,你就必须实现dispose(bool)方法。
用者call close()的时候就会call到你重载的那个dispose(bool)方法去释放资源。
下面是一个标准的继承了idisposable接口类型的实现方式,这种实现我们称之为dispose模式:
public class sampleclass : idisposable
{
//演示创建一个非托管资源
private intptr nativeresource = marshal.allochglobal(100);
//演示创建一个托管资源
private anotherresource managedresource = new anotherresource();
private bool disposed = false;
/// <summary>
/// 实现idisposable中的dispose方法
/// </summary>
public void dispose()
{
//必须为true
dispose(true);
//通知垃圾回收机制不再调用终结器(析构器)
gc.suppressfinalize(this);
}
/// <summary>
/// 不是必要的,提供一个close方法仅仅是为了更符合其他语言(如c++)的规范
/// </summary>
public void close()
{
dispose();
}
/// <summary>
/// 必须,以备程序员忘记了显式调用dispose方法
/// </summary>
~sampleclass()
{
//必须为false
dispose(false);
}
/// <summary>
/// 非密封类修饰用protected virtual
/// 密封类修饰用private
/// </summary>
/// <param name="disposing"></param>
protected virtual void dispose(bool disposing)
{
if (disposed)
{
return;
}
if (disposing)
{
// 清理托管资源
if (managedresource != null)
{
managedresource.dispose();
managedresource = null;
}
}
// 清理非托管资源
if (nativeresource != intptr.zero)
{
marshal.freehglobal(nativeresource);
nativeresource = intptr.zero;
}
//让类型知道自己已经被释放
disposed = true;
}
public void samplepublicmethod()
{
if (disposed)
{
throw new objectdisposedexception("sampleclass", "sampleclass is disposed");
}
//省略
}
}