在 C# 中,类中的析构函数和 Finalize 方法有啥区别?

Posted

技术标签:

【中文标题】在 C# 中,类中的析构函数和 Finalize 方法有啥区别?【英文标题】: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' 使用相同的参数类型

【问题讨论】:

【参考方案1】:

***在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# 本身。【参考方案2】:

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

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

【讨论】:

【参考方案3】:

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

    析构函数

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

    Class MyClass
    
    
    ~MyClass()
    
    .....
    
    
    

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

    处理

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

    完成

    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:如果一个类直接拥有非托管资源并持有对其他对象的引用,则非托管资源通常应拆分为它们自己的可终结类(理想情况下不应持有任何强引用到其他任何东西),这意味着持有对其他对象的引用的类将只拥有“直接拥有非托管资源的东西”,而不是拥有资源本身,因此不需要终结器。

以上是关于在 C# 中,类中的析构函数和 Finalize 方法有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

Java技术专题「原理专题」深入分析Java中finalize方法的作用和底层原理

JVM技术专题「原理专题」深入分析Java中finalize方法的作用和底层原理

析构函数、dispose 和 finalize 方法的区别

java的finalize方法使用

类中的析构函数是否是虚函数

从 C++ 中的析构函数中恢复对象?