C#对象的销毁和IDisposable

1.对象的析构函数与Finalize方法

与C++类似,C#允许程序员为类定义一个”析构函数“:

class MyClass
{
 ~MyClass() //析构函数
 {
 //编写释放非托管的资源
 }
}

上面的代码编译后,可以看到:这里调用了Object类的Finalize方法,这个方法里面是空的,什么也没有。

与构造函数类似,子类的析构函数会自动调用基类的析构函数,由此不断上溯,到最顶层的Object。上面显示了基类的析构函数是在finally里面执行的,这意味着销毁对象是先完成子类的清理工作,在完成基类的清理工作。如果基类没有定义析构函数,则跳过继续向上搜索。当CLR的GC要回收一个定义了析构函数的对象时,它会自动调用Finalize方法,而且调用Finalize方法的时机是不可控的,最好合适的方法就是让程序员主动以完全可控的方式去释放非托管的资源(例如文件句柄,数据库连接)。为此,.NET提供了IDisposable。

IDisposable接口只定义了一个Dispose方法,任何一个希望”手动”回收的非托管资源的类都应该实现该接口。

public interface IDisposable {void Dispose();},因为CLR认为这个接口就是一般的接口,所以不会主动调用。这需要程序员去调用。为了避免资源泄漏,可以这样:

 public class MyClass:IDisposable
 {
 ~MyClass()
 {
 Dispose();
 }

 public void Dispose()
 {
 //
 }
 }

Dispose方法应该允许被调用多次而不能引发异常。可以给出比较安全的代码框架:

MyClass obj = new MyClass();
try
{
 //使用obj对象
}
finally
{
 IDisposable disposable = obj as IDisposable;
 if (obj != null)
 {
 obj.Dispose();//是否资源
 }
}

C#提供了using关键来简化上述代码。using(MyClass obj=new MyClass()){//使用obj}

类的析构函数专用于清理非托管的资源,只有类需要提供一个在应用程序里面可随时调用的“显式”清理资源的功能时,才需要实现IDisposable,然而CLR的GC不会自动调用对象的Dispose()方法,只会调用Finalize方法(也就在析构函数里面)

IDisposable编程模式:

public class MyClass : IDisposable
{
 ~MyClass()
 {
 Dispose();
 }

 public void Dispose()
 {
 Dispose(true);//这样会释放所有的资源
 GC.SuppressFinalize(this);//不需要再调用本对象的Finalize方法
 }

 protected virtual void Dispose(bool disposing)
 {
 if (disposing)
 {
 //清理托管资源
 }
 //清理非托管资源

 }
}

读书笔记《.NET4.0面向对象编程漫谈》作者:金旭亮老师

作者:张雪飞
出处:https://zhangxuefei.site/p/67
版权说明:欢迎转载,但必须注明出处,并在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

发表评论

电子邮件地址不会被公开。 必填项已用*标注