当前位置: 首页 > 图灵资讯 > 技术篇> C#中Finalize方法的问题

C#中Finalize方法的问题

来源:图灵教育
时间:2023-06-06 09:26:37

ninputer在“值类型的finalize不会被调用”中(http://blog.joycode.com/lijianzhong/archive/2005/01/13/42991.aspx#FeedBack)评论说“VB对Finalize管的可松?可直接重写、直接调用、允许不调用父类的Finalize,或多次调用父类的Finalize等... 与C#完全不同。

其实C#的Finalize方法看起来只比VB好一点,但还是有很隐蔽的问题。问题如下。

首先看下面的代码:

using System; public class Grandpapa {      ~Grandpapa(){ Console.WriteLine("Grandpapa.~Grandpapa");} } public class Parent:Grandpapa {      ~Parent(){ Console.WriteLine("Parent.~Parent");} } public class Son:Parent {      ~Son(){ Console.WriteLine("Son.~Son");} } public class App {      public static void Main()      {          Son s=new Son();            GC.Collect();          GC.WaitForPendingFinalizers();      } }

毫无疑问,这个代码的运行结果是:

Son.~Son Parent.~Parent Grandpapa.~Grandpapa

没问题。但如果重新定义Parent类别如下,会发生什么?

public class Parent:Grandpapa {      protected void Finalize(){ Console.WriteLine("Parent.Finalize");} }

运行结果变成:

Son.~Son Parent.Finalize

情况有点糟糕。我在Parent中定义了一种“普通”的Finalize方法,它被它的子类Son分析器调用了?

当然,Finalize方法不是C#中的“普通”方法,而是分析器编译后有上述签名的Finalize方法。然而,C#编译器并没有禁止我们定义“普通”的Finalize,

C#规范没有指出定义这种Finalize的方法是定义一个分析器——事实上,它不是,但上述代码的性能——甚至有这样一个诱人的错误:The compiler behaves as if this method(Finalize), and overrides of it, do not exist at all。从分析IL代码可以看出,Parent中定义的“普通”Finalize方法实际上“欺骗”了它的子类。从分析IL代码可以看出,Parent中定义的“普通”Finalize方法实际上“欺骗”了它的子类。它的子类只关心它的父类是否定义了Finalize(当然,签名应该是以上形式),而不关心Finalize方法是否具有“分析器”的含义。

如果通过理性分析可以接受上述代码的行为,则以下代码的运行结果令人头晕。重新定义Parent类别如下(在上述基础上添加virtual关键字):

public class Parent:Grandpapa {      protected virtual void Finalize(){ Console.WriteLine("Parent.Finalize");} }

编译后的操作结果如下:

Grandpapa.~Grandpapa

C#中Finalize方法的问题_App

C#中Finalize方法的问题_App_02

C#中Finalize方法的问题_父类_03