老生常谈的问题了,MSDN也有很是详细的说明但看起来不是很系统。也曾经作过度析,但没有总结下来又忘了,此次整理一下MSDN和网上搜集的一些资料,以备不时只需。程序员
下面是MSDN对这两个函数的建议使用方法数据库
1 // Design pattern for a base class. 2 public class Base : IDisposable 3 { 4 //保证重复释放资源时系统异常 5 private bool _isDisposed = false; 6 7 // 析构函数,编译器自动生成Finalize()函数由GC自动调用,保证资源被回收。 8 // 最好不要声明空析构函数,形成性能问题 9 // 若是没有引用非托管资源就不须要显示声明析构函数,会形成性能问题,系统会自动生成默认析构函数 10 ~Base() 11 { 12 // 此处只须要释放非托管代码便可,由于GC调用时该对象资源可能还不须要释放 13 Dispose(false); 14 } 15 16 //外部手动调用或者在using中自动调用,同时释放托管资源和非托管资源 17 public void Dispose() 18 { 19 Dispose(true); 20 GC.SuppressFinalize(this); ///告诉GC不须要再次调用 21 } 22 23 protected virtual void Dispose(bool disposing) 24 { 25 if (!_isDisposed) 26 { 27 if (disposing) 28 { 29 //释放托管资源 30 } 31 // 释放非托管资源 32 // 释放大对象 33 34 this._isDisposed = true; 35 } 36 37 } 38 39 }
下面是经过Reflector工具对上面代码反射出来的结果,能够看出析构函数直接被翻译成Finalize()函数了,由于Finalize函数不能被重写,因此只能用析构函数的方式实现Finalize方法。编程
1 public class Base : IDisposable 2 { 3 // Fields 4 private bool _isDisposed; 5 6 // Methods 7 public Base(); 8 public void Dispose(); 9 protected virtual void Dispose(bool disposing); 10 protected override void Finalize(); 11 }
在.NET的对象中实际上有两个用于释放资源的函数:Dispose和Finalize。Finalize的目的是用于释放非托管的资源,而Dispose是用于释放全部资源,包括托管的和非托管的。安全
在这个模式中,void Dispose(bool disposing)函数经过一个disposing参数来区别当前是不是被Dispose()调用。若是是被Dispose()调用,那么须要同时释放 托管和非托管的资源。若是是被~Base()(也就是C#的Finalize())调用了,那么只须要释放非托管的资源便可。编程语言
这是由于,Dispose()函数是被其它代码显式调用并要求释放资源的,而Finalize是被GC调用的。在GC调用的时候Base所引用的其它托管对象可能还不须要被销毁,而且即便要销毁,也会由GC来调用。所以在Finalize中只须要释放非托管资源便可。另一方面,因为在 Dispose()中已经释放了托管和非托管的资源,所以在对象被GC回收时再次调用Finalize是没有必要的,因此在Dispose()中调用 GC.SuppressFinalize(this)避免重复调用Finalize。ide
然而,即便重复调用Finalize和Dispose也是不存在问题的,由于有变量_isDisposed的存在,资源只会被释放一次,多余的调用会被忽略过去。所以,上面的模式保证了:函数
一、 Finalize只释放非托管资源;工具
二、 Dispose释放托管和非托管资源;性能
三、 重复调用Finalize和Dispose是没有问题的;this
四、 Finalize和Dispose共享相同的资源释放策略,所以他们之间也是没有冲突的。
微软对Dispose和Finalize方法使用准则
Finalize
下面的规则归纳了 Finalize 方法的使用准则:
一、不能在结构中定义析构函数。只能对类使用析构函数。
二、一个类只能有一个析构函数。
三、没法继承或重载析构函数。
四、没法调用析构函数。它们是被自动调用的。
五、析构函数既没有修饰符,也没有参数。
注意
基类的 Finalize 方法经过 C# 和 C++ 析构函数语法自动进行调用。
释放
下面的规则归纳了 Dispose 方法的使用准则:
下面是CSDN高手总结
一、Finalize方法(C#中是析构函数,如下称析构函数)是用于释放非托管资源的,而托管资源会由GC自动回收。因此,咱们也能够这样来区分 托管和非托管资源。全部会由GC自动回收的资源,就是托管的资源,而不能由GC自动回收的资源,就是非托管资源。在咱们的类中直接使用非托管资源的状况很 少,因此基本上不用咱们写析构函数。
二、大部分的非托管资源会给系统带来不少负面影响,例如数据库链接不被释放就可能致使链接池中的可用数据库链接用尽。文件不关闭会致使其它进程没法读写这个文件等等。
实现模型:
一、因为大多数的非托管资源都要求能够手动释放,因此,咱们应该专门为释放非托管资源公开一个方法。实现IDispose接口的Dispose方法是最好的模型,由于C#支持using语句快,能够在离开语句块时自动调用Dispose方法。
二、虽然能够手动释放非托管资源,咱们仍然要在析构函数中释放非托管资源,这样才是安全的应用程序。不然若是由于程序员的疏忽忘记了手动释放非托管资源, 那么就会带来灾难性的后果。因此说在析构函数中释放非托管资源,是一种补救的措施,至少对于大多数类来讲是如此。
三、因为析构函数的调用将致使GC对对象回收的效率下降,因此若是已经完成了析构函数该干的事情(例如释放非托管资源),就应当使用SuppressFinalize方法告诉GC不须要再执行某个对象的析构函数。
四、析构函数中只能释放非托管资源而不能对任何托管的对象/资源进行操做。由于你没法预测析构函数的运行时机,因此,当析构函数被执行的时候,也许你进行操做的托管资源已经被释放了。这样将致使严重的后果。
五、(这是一个规则)若是一个类拥有一个实现了IDispose接口类型的成员,并建立(注意是建立,而不是接收,必须是由类本身建立)它的实例对象,则 这个类也应该实现IDispose接口,并在Dispose方法中调用全部实现了IDispose接口的成员的Dispose方法。
只有这样的才能保证全部实现了IDispose接口的类的对象的Dispose方法可以被调用到,确保能够手动释听任何须要释放的资源。