在 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方法的作用和底层原理