【问题标题】:In C# what is the difference between a destructor and a Finalize method in a class?在 C# 中,类中的析构函数和 Finalize 方法有什么区别?
【发布时间】:2010-11-07 19:08:49
【问题描述】:

类中的析构函数和 Finalize 方法之间有什么区别(如果有的话)?

我最近发现 Visual Studio 2008 将析构函数视为 Finalize 方法的同义词,这意味着 Visual Studio 不允许您在一个类中同时定义这两种方法。

例如下面的代码片段:

class TestFinalize
{
    ~TestFinalize()
    {
        Finalize();
    }

    public bool Finalize()
    {
        return true;
    }
}

在析构函数中调用 Finalize 时出现以下错误:

以下方法或属性之间的调用不明确: 'TestFinalize.~TestFinalize()'和'TestFinalize.Finalize()'

如果对 Finalize 的调用被注释掉,则会出现以下错误:

类型“ManagementConcepts.Service.TestFinalize”已经定义了一个名为 'Finalize' 使用相同的参数类型

【问题讨论】:

    标签: c# destructor finalize


    【解决方案1】:

    C# 中的析构函数会覆盖 System.Object.Finalize 方法。您必须使用析构函数来这样做。手动覆盖Finalize 会给你一个错误信息。

    基本上你试图用你的Finalize 方法声明做的是hiding 基类的方法。它将导致编译器发出警告,可以使用 new 修饰符(如果它可以工作)将其静音。这里要注意的重要一点是,您不能同时声明 override 和具有相同名称的 new 成员,因此将导致同时具有析构函数和 Finalize 方法出现错误(但您可以声明 public new void Finalize() 方法,尽管不推荐,但如果您不声明析构函数)。

    【讨论】:

      【解决方案2】:

      维基百科在finalizer 文章中对终结器和destructor 之间的区别进行了很好的讨论。

      C# 确实没有“真正的”析构函数。语法类似于 C++ 析构函数,但它确实是终结器。您在示例的第一部分中正确编写了它:

      ~ClassName() { }
      

      以上是Finalize 函数的语法糖。它确保基础中的终结器保证运行,但在其他方面与覆盖 Finalize 函数相同。这意味着当您编写析构函数语法时,您实际上是在编写终结器。

      According to Microsoft,终结器是指垃圾收集器在收集时调用的函数(Finalize),而析构函数是您执行的代码(变成Finalize的语法糖) .它们是如此接近于相同的东西,以至于微软本不应该做出区分。

      Microsoft 对 C++ 的“析构函数”术语的使用具有误导性,因为在 C++ 中,只要对象被删除或从堆栈中弹出,它就会在同一个线程上执行,而在 C# 中,它会在另一个线程上的单独线程上执行时间。

      【讨论】:

      • 我认为析构函数和终结器之间的这种区别很重要。然而,只有那些关心幕后发生的事情的人才会关心所说的区别。
      • 另请注意,ECMA-334 很久以前就正式明确地消除了“析构函数”和“终结器”的歧义。我不知道为什么 MS 在他们的规范中仍然坚持使用误导性术语。
      • 至少从使用 Mono 来看,C# 实际上是仿照 C++ 建模的,而且大多数原生 C# 对象都是 C++ 对象。编译 Mono 的编译器的工作方式决定了这些 C++ 对象如何被破坏,同样,C# 对象终结如何传播到 C++ 并调用这些析构函数。这种区别在幕后是有道理的,但它仍然不适用于 C# 本身。
      【解决方案3】:

      Found here: http://sanjaysainitech.blogspot.com/2007/06/difference-between-destructor-dispose.html

      1. 析构函数

        它们是包含对象清理代码的特殊方法。 您不能在代码中显式调用它们,因为它们被调用 由 GC 隐含。在 C# 中,它们与前面的类名具有相同的名称 通过~ 符号。喜欢-

        Class MyClass
        {
        
        ~MyClass()
        {
        .....
        }
        }
        

        在 VB.NET 中,析构函数是通过重写 Finalize 来实现的 System.Object 类的方法。

      2. 处理

        这些就像类中的任何其他方法一样,可以调用 明确但他们有清理对象的特殊目的。 在 dispose 方法中,我们为对象编写清理代码。它是 重要的是我们释放了 dispose 中的所有非托管资源 数据库连接,文件等方法。实现的类 dispose 方法应该实现 IDisposable 接口。Dispose 方法 应该为它所在的对象调用 GC.SuppressFinalize 方法 处置该类是否具有破坏者,因为它已经完成了 努力清理对象,那么垃圾就没有必要了 收集器调用对象的 Finalize 方法。参考: http://msdn2.microsoft.com/en-us/library/aa720161(VS.71).aspx

      3. 完成

        Finalize 方法作为一种安全措施来清理 未调用您的 Dispose 方法的事件。你应该只 实现一个 Finalize 方法来清理非托管资源。你 不应为托管对象实现 Finalize 方法,因为 垃圾收集器自动清理托管资源。 GC 隐式调用 Finalize 方法,因此您不能 从您的代码中调用它。

        注意:在C#中,Finalize方法不能被覆盖,所以你必须 使用析构函数,其内部实现将覆盖 MSIL中的Finalize方法。但是在VB.NET中,Finalize方法可以 覆盖,因为它确实支持析构方法。

      更新: Interesting semi-related thread here.

      【讨论】:

      • You should only implement a Finalize method to clean up unmanaged resources :你把它放在 Finalize 中。与 Dispose 相同?
      • @hqt:应该实现Dispose 的情况远远多于应该实现终结器的情况。实现Dispose 如果类或派生类的实例可能是最后一个直接拥有非托管资源,或直接拥有最后一个直接拥有非托管资源,或直接拥有最后一个直接拥有等。仅当一个类直接拥有非托管资源几乎没有其他资源时才实施Finalize进行资源清理——这是一个更窄的场景。
      • @hqt:如果一个类直接拥有非托管资源并持有对其他对象的引用,则非托管资源通常应拆分为它们自己的可终结类(理想情况下不应持有任何强引用到其他任何东西),这意味着持有对其他对象的引用的类将只拥有“直接拥有非托管资源的东西”,而不是拥有资源本身,因此不需要终结器。
      猜你喜欢
      • 2011-01-16
      • 2012-12-08
      • 1970-01-01
      • 1970-01-01
      • 2013-05-30
      • 2015-05-02
      相关资源
      最近更新 更多