C#中的继承和析构函数

use*_*041 12 c# inheritance destructor

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

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

}

class B : A
{

}

B b = new B();
Run Code Online (Sandbox Code Playgroud)

什么时候B被破坏,它的析构函数不会被调用?

Eri*_*ert 42

据此,它声明Destructors不能被继承或过载.

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

在我的例子中,对于所有子类,析构函数将是相同的.

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

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

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

我无法在基类中声明析构函数并使处理具有破坏性?

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

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

那是不对的.

在我看来,你自己尝试的时间要少得多,而不是在这里提问并等待回应.

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

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

当收集器确定某个对象无法从gc根目录中访问时,该对象具有一个尚未被抑制的终结器,则该对象通过将其放置在终结队列上以由终结器线程进行服务来提升到下一代.如果没有,它的内存将被回收.

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

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

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

我什么时候应该创建一个析构函数?

  • 嘿Eric,我已经把你的答案标记为粗鲁,如果再读一遍,我想你会同意的.也许你有一个糟糕的一天?:) OP似乎来自C++,这将使这个问题非常合理. (6认同)
  • 你是什​​么意思"引用可能是死的东西".保证所有对象引用都指向有效的.net对象; 如果任何一个具有直接或间接引用的对象覆盖Finalize并且没有抑制终结,则可能它们可能已经运行或被安排运行,但只要一个对象被注册用于最终化,它既不是它也不是任何对象它可以从内存中删除它所持有的直接或间接引用.最终确定的最大困难可能是未知的线程上下文. (2认同)
  • 对象不应该对代码一不能控制的可终结对象的状态做出任何假设,但如果Class1和Class2都在同一个程序集中,并且Object1(类型为Class1)保存对Object2(Class2)的引用和访问它在终结器中,必须为Object2可能已经完成的可能性做好准备,或者可能正在等待最终确定.如果对Object2的任何引用已在外部公开,则它还必须允许对Object2的外部实时引用可能仍然存在.但是,受这些限制,...... (2认同)
  • ...对象具有相互协调的终结器是完全可能和合理的.我花了一段时间才理解GC循环如何将对象划分为除了最终化机制以外的根,对于已完成注册但没有*其他*根的对象,以及那些根本没有根参考的对象,以及理解终结不会以任何方式干扰对象,除了调用Finalize(它只会以明确编程的方式干扰对象). (2认同)
  • @Seth:我坚持答案.我从来没有说过这个问题是不合理的.答案是准确和有帮助的. (2认同)

har*_*357 18

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

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

  • 从技术上讲,C#规范称它为析构函数.(就我个人而言,我认为这是一个误导性的名称,即使在C#规范中也应称为终结者) (6认同)
  • 我认为在大多数情况下使用IDisposable的概念 (2认同)

dri*_*iis 7

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

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