一、析构函数
析构函数(destructor)用于析构类的实例。即在类的实例被销毁之前,执行资源的清理或者释放非托管资源。下面的代码示例中声明了一个名为Car的类,该类包含一个名为~Car的析构函数:
1 class Car 2 { 3 ~Car() // destructor 4 { 5 // 执行清理 6 } 7 }
析构函数的特征如下:
1.不能在结构中定义析构函数。只能对类使用析构函数。
2.每个类只能有一个析构函数。
3.析构函数名为:"~"+类名,比如~Car。
4.析构函数不能带访问修饰符。
5.析构函数不能带参数,自然也无法重载。
6.析构函数是用来析构类的实例的,因此没有静态析构函数。
7.不能显式调用析构函数。析构函数是在垃圾收集过程中被自动调用的:如果垃圾回收器认为某个对象符合析构,则调用析构函数(如果有)并回收用来存储此对象的内存。程序退出时也会调用析构函数。
8.该析构函数隐式地对对象的基类调用 Finalize。反编译上例的类Car,得到下面的结果:
1 internal class Car 2 { 3 // Methods 4 public Car(); 5 protected override void Finalize(); 6 }
该代码包括一个构造函数和一个重写的Finalze方法,其实这就是构造函数编译之后的代码。
下面是另外一个析构函数的示例:下面的示例创建三个类,这三个类构成了一个继承链。类 First 是基类,Second 是从 First 派生的,而 Third 是从 Second 派生的。这三个类都有析构函数。在 Main() 中,创建了派生程度最大的类的实例。注意:程序运行时,这三个类的析构函数将自动被调用,并且是按照从派生程度最大的到派生程度最小的次序调用。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 class First 2 { 3 ~First() 4 { 5 System.Diagnostics.Trace.WriteLine("First's destructor is called."); 6 } 7 } 8 9 class Second : First 10 { 11 ~Second() 12 { 13 System.Diagnostics.Trace.WriteLine("Second's destructor is called."); 14 } 15 } 16 17 class Third : Second 18 { 19 ~Third() 20 { 21 System.Diagnostics.Trace.WriteLine("Third's destructor is called."); 22 } 23 } 24 25 class Program 26 { 27 static void Main(string[] args) 28 { 29 Third t = new Third(); 30 31 /* 输出结果 (在 VS 的输出窗口中可以看到): 32 Third's destructor is called. 33 Second's destructor is called. 34 First's destructor is called. 35 */ 36 } 37 }
二、何时使用析构函数?
通常,与运行时不进行垃圾回收的开发语言相比,C# 无需太多的内存管理。这是因为 .NET Framework 垃圾回收器会隐式地管理对象的内存分配和释放。但是,当应用程序封装窗口、文件和网络连接这类非托管资源时,应当使用析构函数释放这些资源。当对象符合析构时,垃圾回收器将运行对象的 Finalize 方法。
三、显式释放资源
如果代码中包含了需要及时释放的非托管资源,就不能使用析构函数实现,因为析构函数不能显式调用,我们不能确定它什么时候才能被GC调用,所以是不可控制的。对于这种情况,我们可以实现IDisposable接口。只要类实现了IDisposable即可,就可以调用它的Dispose方法来释放非托管资源。关于IDisposable接口和资源释放的更多内容,我会在以后的文章中继续研究。
参考:http://msdn.microsoft.com/zh-cn/library/66x5fx1b(VS.100).aspx