9.13 析构函数

析构函数的作用是在类被销毁之前,对类实例使用的托管或非托管资源进行释放。通常,与运行时不进行垃圾回收的开发语言相比,C#无须太多的内存管理。这是因为.NET Framework垃圾回收器会隐式地管理对象的内存分配和释放。但是,当应用程序封装窗口、文件和网络连接这类非托管资源时,应当使用析构函数释放这些资源。

析构函数具有如下特点:

❑析构函数不能有访问修饰符;

❑析构函数不能有参数;

❑一个类只能有一个析构函数;

❑无法继承或重载析构函数;

❑无法调用析构函数;

❑无法预知析构函数何时被调用,因为它是被自动调用的。

接下来,看一个析构函数示例,如代码清单9-37所示。

代码清单9-37 析构函数


~Car()

{

System.Console.WriteLine(“析构函数调用了!”);

}


然后,看一下这个析构函数编译生成CIL后的结构,注意一点,析构函数编译成CIL后转化为了Finalize方法,如图9-12所示。

9.13 析构函数 - 图1

图 9-12 Car类的析构函数转换为了Finalize方法

代码清单9-38 是析构函数Finalize方法的CIL代码。

代码清单9-38 析构函数的CIL代码


.method family hidebysig virtual instance void

Finalize()cil managed

{

//Code size 25(0x19)

.maxstack 1

.try

{

IL_0000:nop

IL_0001:ldstr bytearray(90 67 84 67 FD 51 70 65 03 8C 28 75 86 4E 01 FF)

//.g.g.Qpe……(u.N……

IL_0006:call void[mscorlib]System.Console:WriteLine(string)

IL_000b:nop

IL_000c:nop

IL_000d:leave.s IL_0017

//end.try

finally

{

IL_000f:ldarg.0

IL_0010:call instance void[mscorlib]System.Object:Finalize()

IL_0015:nop

IL_0016:endfinally

}//end handler

IL_0017:nop

IL_0018:ret

}//end of method Car:Finalize


先从较高的视角观察代码清单9-38的整体结构,它使用了try-finally语句,在try块中获取并使用资源,并在finally块中释放资源,如下:


try{

//执行语句

}finally{

//这里的代码一定会被执行

}


这表示,析构函数中编写的代码被移到了try语句块中,而在finally语句块中添加了对基类的Finalize()方法的调用,这意味着将会对继承链中的所有实例递归地调用Finalize方法(从子类到基类)。

前面的析构函数代码被隐式地转换为以下代码:


protected override void Finalize()

{

try

{

//执行清理操作的语句

}

finally

{

base.Finalize();

}

}