C#中的继承和析构函数

时间:2011-11-17 21:09:52

标签: c# inheritance destructor

根据this,它指出Destructors cannot be inherited or overloaded.在我的情况下,对于所有子类,析构函数将是相同的。这几乎告诉我,我必须在每个子类中定义相同的析构函数。我无法在基类中声明析构函数并使处理具有破坏性?说我有这样的事情:

class A
{
    ~A()
    {
        SomethingA();
    }

}

class B : A
{

}

B b = new B();

B被销毁时,它的析构函数不会被调用?

7 个答案:

答案 0 :(得分:42)

  

根据这一点,它声明Destructors不能被继承或重载。

正确。析构函数不是可继承的成员,并且不是虚拟的,因此不能被覆盖。它们总是具有相同的签名,因此不会超载。

  

就我而言,对于所有子类,析构函数都是相同的。

您提出这样一个基本问题的事实告诉我您不应该首先实现析构函数。正确实现析构函数是C#中最难做的事情之一在除了最微不足道的案件之外的所有案件中。为什么你认为你需要实现析构函数?

  

这是否告诉我,我必须在每个子类中定义相同的析构函数?

不,一点也不。你是如何从析构函数不被继承的事实得出这个结论的?

  

我无法在基类中声明析构函数并将句柄解压缩?

当然,这是一件明智的事情,只要你一开始就倾向于实现析构函数。

  

当B被销毁时,它的析构函数不会被调用?

这是不正确的。

在我看来,你自己尝试的时间比在这里提出问题并等待回应的时间少得多。

  

析构函数何时实际被调用?当变量超出范围时,它是否在垃圾收集中?

我之前的推测是正确的。 在您深入了解整个垃圾收集过程之前,您绝对不应该实现析构函数。例如,您认为变量在超出范围时收集的事实表明您没有深刻理解这一点,写出正确的析构函数。

当收集器确定某个对象无法从gc根目录中访问,并且该对象具有一个尚未被抑制的终结器时,该对象将被放置在终结队列上,以便通过该对象进行维护,从而将该对象提升为下一代。终结者线程。如果没有,则回收其内存。

当终结器线程开始运行时,它会运行该对象的所有析构函数。 (析构函数将按照从大多数派生到最少派生的顺序运行。)在该过程之后,对象可能会或可能不会无法访问,并且可能会或可能不会抑制终结。如果确定该对象无法访问,则整个过程再次开始。

我无法强调您为了正确执行此操作而需要了解GC流程的程度。当你编写析构函数时,它会在没有意义的环境中运行。对象中的所有引用可能是仅由终结器队列生根的对象;通常所有参考都是为了生活。引用可能是已经完成的对象。析构函数在不同的线程上运行。即使构造函数失败,析构函数也会运行,因此对象可能甚至不能构造非原子值类型的字段可能只是部分写入 - 当一个线程被中止时,双字段完全有可能只有四个字节由构造函数设置;终结器将看到部分写入的字段。即使对象因中止的事务而处于不一致状态,析构也会运行。等等。在编写析构函数时,你必须极其防御

这个答案也可能会有所帮助:

When should I create a destructor?

答案 1 :(得分:18)

它不是C#中的析构函数。它被称为Finializer;当它被调用时是非确定性的。实际上你根本不能指望它被调用。

终结器用作清理非托管资源的最后手段。您应该查看Dispose pattern

答案 2 :(得分:7)

当B的实例被销毁时,将在A中定义终结器。

如果在A和B中定义终结器,则最具体的终结器(B)将首先运行,然后运行最不具体的(A)。

答案 3 :(得分:2)

我已经做了近十年的.NET编程。 时间我实现了终结器,它最终成为内存泄漏的原因而没有别的。你几乎从不需要它们。

答案 4 :(得分:0)

如果为B定义析构函数,则会调用它,然后是A。请参阅example at the bottom of the link you provided

答案 5 :(得分:0)

好吧,我不知道析构函数,但你有其他有用的方法可以清理IDisposable中的Finalize()和Dispose()。

答案 6 :(得分:0)

快速控制台应用程序可以帮助测试这种情况。

using System;

class A
{
    ~A() => Console.WriteLine("~A");       
}

class B : A
{
    ~B() => Console.WriteLine("~B");
}

public class Program
{
    public static void Main() => new B();        
}

输出可能是...

~B
~A