C# 语言规范 3.0的第 10.13 节,析构函数声明如下:
析构函数不是继承的。因此,除了可以在该类中声明的析构函数之外,一个类没有析构函数。
C# 编程指南的析构函数部分包含一个示例,演示如何调用继承层次结构中的析构函数,包括以下语句:
... ...类的析构函数被自动调用,并且按从最派生到最不派生的顺序。
我已经通过各种实际示例对此进行了研究,包括一个具有定义析构函数的基类,以及从基类继承但未定义析构函数的派生类。创建派生类的实例,允许对该实例的所有引用超出范围,然后强制进行垃圾回收,这表明当派生类的实例最终确定时,将调用基类中定义的析构函数。
我的问题是“不继承析构函数”实际上是什么意思,因为虽然你不能显式调用析构函数,但继承链中的析构函数会自动调用,并且即使派生类没有定义析构函数也会调用基类析构函数?
它是否与一些微妙的语义区别有关,即终结是由垃圾收集器而不是 C# 语言/编译器实现的?
编辑1:
虽然 C# 语言规范还声明“实例构造函数不被继承”,但与构造函数相关的行为与析构函数有很大不同,并且更适合 IMO 与“不继承”术语,如下例所示:
public class ConstructorTestBase
{
public ConstructorTestBase(string exampleParam)
{
}
}
public class ConstructorTest: ConstructorTestBase
{
public ConstructorTest(int testParam)
: base(string.Empty)
{
}
}
...
// The following is valid since there is a derived class constructor defined that
// accepts an integer parmameter.
ConstructorTest test1 = new ConstructorTest(5);
// The following is not valid since the base class constructor is not inherited
// by the derived class and the derived class does not define a constructor that
// takes a string parameter.
ConstructorTest test2 = new ConstructorTest("Test");
与析构函数相关的行为与此非常不同,如以下示例所示,该示例通过仅向基类添加析构函数来扩展前面的构造函数示例。
public class ConstructorTestBase
{
public ConstructorTestBase(string exampleParam)
{
}
~ConstructorTestBase()
{
Console.WriteLine("~ConstructorTestBase()");
}
}
...
ConstructorTest test1 = new ConstructorTest(5);
test1 = null;
GC.Collect();
上面的示例演示了当派生类的实例完成时将调用基类构造函数,即使派生类没有显式定义析构函数。
我的观点很简单,我遇到过很多人没有意识到或不理解会发生这种情况,其中很大一部分原因是“析构函数不是继承的”声明。
编辑2:
C# 语言规范还说明了以下内容并提供了底层实现的代码示例:
析构函数是通过覆盖 System.Object 上的虚拟方法 Finalize 来实现的。不允许 C# 程序覆盖此方法或直接调用它(或覆盖它)。
由于引擎盖下的实现实际上是基于继承的,如上所述,我认为我的问题是有效的,我认为到目前为止我收到的任何回复都没有正确解决这个问题 - 什么“析构函数不是继承的”实际上是什么意思?