为什么不允许Finalize方法覆盖

时间:2010-04-06 17:42:09

标签: c# .net

我是.net的新手。我对C#中的析构函数机制感到困惑。请澄清

在C#中,析构函数由CLR转换为finalize方法。 如果我们尝试覆盖它(不使用析构函数),将会出错 错误2不要覆盖object.Finalize。相反,提供一个析构函数。

但似乎mscorlib.dll中的Object calss实现已将finalize定义为protected override void Finalize(){},那么为什么我们无法覆盖它,那是什么虚函数。

为什么设计是这样的,它是否与c ++析构函数概念一致。

当我们转到对象类的定义时,没有提到finalize方法,那么hmscorlib.dll定义如何显示finalize函数。 这是否意味着将默认析构函数转换为finalize方法。

public class Object
{     

    public Object();
    public virtual bool Equals(object obj);        
    public static bool Equals(object objA, object objB);       
    public virtual int GetHashCode();       
    public Type GetType();      
    protected object MemberwiseClone();  
    public static bool ReferenceEquals(object objA, object objB);
    public virtual string ToString();
}

5 个答案:

答案 0 :(得分:20)

  

我是.NET的新手,我对C#中的析构函数机制感到困惑。请澄清。

不确定。我同意这令人困惑。

  

在C#中,析构函数由CLR转换为finalize方法。

正确。好吧,我会说这是由C#编译器完成的,而不是CLR,但我理解你的意思。

  

如果我们尝试覆盖它(不使用析构函数),则会收到错误“不要覆盖object.Finalize。而是提供析构函数。”

正确。

  

似乎mscorlib.dll中的Object类实现已将finalize定义为protected override void Finalize(){}

正确。

  那么为什么我们不能覆盖呢?这就是虚拟功能的用途。

因为那时会有两种方式来编写析构函数。那会令人困惑。我们希望只有一种方法来编写析构函数。

  

为什么这样的设计?是否与c ++析构函数概念一致?

这是一个原因,是的。还有其他原因。以下是一些:

  • 通过逻辑分离“析构函数”和“覆盖终结方法”的概念,我们可以通过其他环境中的其他机制实现析构函数。这还没有发生,但是未来我们可能会编写一个C#版本,比如用于在具有与标准CLR语义不同的垃圾收集器语义的环境中构建设备驱动程序。在该环境中,析构函数的语义可能更像是C ++析构函数的语义,而不像GC终结器。

  • 终结者是非常特殊的方法。你不能像常规方法那样称呼它们;只有垃圾收集器可以调用它们。他们有不同的异常处理规则。它们必须确保在派生类终结器之后严格调用基类终结器。它们非常特殊,将它们暴露为任何其他方法似乎很危险。如果你有一种方法只是坐在那里你可以打电话,你可以把任何你想要的东西,等等,这使得很容易忘记终结者的特殊性。使用特殊语法强调这是特殊代码。

  

另外,当我们转到对象类的定义时,没有提到finalize方法,那么mscorlib.dll定义如何显示finalize函数。

假设我们在对象浏览器中显示了一个名为MagicUnicorn的方法,如果您尝试调用它或覆盖它,则会收到错误消息“不要这样做!”。如果你不能做任何事情,为什么还要费心去展示MagicUnicorn方法呢?那只是无益的噪音。

现在,如果您反汇编mscorlib,那么当然确实存在特殊的Finalize方法。

  

是否意味着将默认析构函数转换为finalize方法。

答案 1 :(得分:4)

'为什么会这样?'   通过设计决定。可能与C ++相匹配,但它确实无关紧要。

  

hmscorlib.dll如何定义   显示最终化函数

C#编译器可能有一个特殊的干预。同样,它没有实际的区别。

如果你真的需要一个终结器,那就写一个析构函数。更重要的是:你几乎不需要。

要了解这个选择是多么随意:在VB中你可以override Finalize。这两种语言可以非常愉快地使用(并继承)其他类型的语言。

答案 2 :(得分:0)

要覆盖Finalize(),您必须使用终结器语法。 CLI在内部对某些事物使用固定名称,例如名为.ctor所有实例构造函数,以及名为.cctor的所有静态构造函数。当C#编译器编写输出程序集时,它确保为它发出的项使用正确的名称,其中包括将析构函数编写为名称为Finalize()而不是~T()。其他.NET语言的编译器也必须遵循这些相同的规则来处理它们自己的语义。

class A
{
    ~A() { /* ... */ }
}

关于终结者的时间和方式,请在此处查找有关终结者和IDisposable的许多其他问题。

答案 3 :(得分:0)

  

是否意味着将默认析构函数转换为finalize方法

是的,C#中的默认(且唯一)析构函数语法被编译为Finalize方法。这很可能为C ++开发人员提供熟悉的语法。有关详细信息,请参阅Destructors on MSDN

答案 4 :(得分:0)

在C ++中,您需要析构函数是虚拟的。原因是,这就是它被调用的方式

A a = new B() //where B derived from A
delete a;

C ++上有点生疏,如果我错了,请原谅我。但是请注意,删除传递的引用可能是基类。

在C#中,您不会调用终结器。它由垃圾收集器在内部调用。垃圾收集器没有理由对之前分配的引用类型感兴趣,并直接获取对象:)

现在,终结器只是从C ++中获取语法。因此混乱。

其他人说的是,您通常不需要最终确定。这就是原因。

如果实现IDisposable,您可以获取“using”语句的帮助来决定变量的范围并在需要时进行处理。使用Finalization时,GC将决定何时调用该方法。这意味着,如果您需要释放资源,时机可能是错误的。

希望这会有所帮助。