为什么不允许Finalize方法覆盖

我是.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(); } 

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

当然。 我同意这令人困惑。

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

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

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

正确。

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

正确。

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

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

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

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

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

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

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

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

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

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

是。

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

hmscorlib.dll定义如何显示finalize函数

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

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

要查看这个选项有多随意:在VB中你可以覆盖Finalize 。 这两种语言可以非常愉快地使用(并inheritance)其他类型的语言。

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

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

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

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

关于终结器的时间和方式,请查看处理终结器和IDisposable的许多其他问题。

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

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

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

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

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

其他人说的是,你通常不需要敲定。 这就是为什么。

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

希望这可以帮助。