【问题标题】:Finalizers and destructors, what's Wikipedia saying?终结器和析构器,维基百科在说什么?
【发布时间】:2011-08-18 11:18:46
【问题描述】:

据我所知,关于这个问题有两个阵营 - 第一个认为终结器是 C# 特有的析构函数。所以他们认为这两件事是一样的。

第二个阵营认为存在细微差别——在维基百科中写道——““析构函数”一词通常用于表示确定性调用的清理,而“终结器”在垃圾收集器要求运行时运行。”

但让我为自己澄清一些事情。确定性调用的清理?在 C# 规范和 msdn 中写到不能调用析构函数(它们是自动调用的)。唯一可以自动调用它们的情况是垃圾收集器。

所以我看不出确定性调用的清理和垃圾收集器的情况有什么区别。

是这样还是不是?

【问题讨论】:

    标签: c# destructor finalizer


    【解决方案1】:

    有很大的不同。 确定性调用意味着你知道它何时会被调用。

    在 C++ 中:

    {
        Person a;
        a.Name = "John";
        InvitePerson(a);
    } // <-- Destructor is always invoked when the scope is left
    

    在 C# 中:

    {
        Person a = new Person();
        a.Name = "John";
        InvitePerson(a);
    } // <-- The finalizer is NOT invoked when the scope is left
    

    正如所指出的,主要区别是:
    在 C# 和其他垃圾回收语言中,您不知道 何时 甚至 是否 将执行终结器。
    然而,在 C++ 中,您确实知道 when 只要对象超出范围,就会执行析构函数。

    【讨论】:

    • 那么 C# 中的析构函数呢?
    • 最接近的是IDisposable.Dispose
    • 那么,C#中没有析构函数吗?
    • 最接近的是IDisposable.Dispose。至少如果您指的是维基百科中的析构函数。正如其他人所指出的,即使在 C# 规范中也有称为析构函数的终结器......回答你的问题:不,在维基百科或 C++ 中没有析构函数。您需要使用 IDisposable.Disposeusing() 块来模拟它。
    【解决方案2】:

    官方的立场是 C# 有析构函数 (~ClassName() {}),它们映射到 System.Object.Finalize()。在 VB.NET 中,您只需像 ToString 一样覆盖 Finalize。

    虽然有些混乱,但你是对的。但更多的是关于 Finalize/Destructor vs Dispose。这里是a post from Eric Lippert(参考维基百科):

    是的,根据这些定义,C# 规范 弄错了。我们所说的 规范中的“析构函数”实际上是 终结器,我们称之为 由 a 调用的“Dispose()”方法 “using”语句实际上是一个 “析构函数”。

    【讨论】:

      【解决方案3】:

      在 C# 中,终结器和析构器是同一事物的不同名称。

      C# 语言规范 (1.6.7.6) 实际上将这些称为析构函数。但是,由于名称析构函数很容易被误认为是 C++ 对应项(这与 C# 中的析构函数完全不同),因此使用术语终结器是有意义的。

      【讨论】:

      • 这就是为什么我对这个话题如此困惑blogs.msdn.com/b/ericlippert/archive/2010/01/21/…
      • @Sergey:您对此有何困惑? Eric Lippert 指出,根据 Wikipedia 上的定义,语言规范使用了不正确的术语。
      • 那么,我们应该相信谁——语言规范还是维基百科?
      • @Sergey:它们都可能是正确的。维基百科给出了这些词的一般定义。 C# 规范详细说明了语言的定义。在这种情况下,即使定义与 Wikipedia 定义的术语不匹配,该定义仍然有效。因此,根据维基百科,在 C# 中,析构函数是终结器。正如 Eric Lippert 指出的那样,规范命名错误。
      • 它们并不完全相同。类的析构函数是一段代码,它将请求编译器生成 Object.Finalize() 的覆盖(即终结器),其中包含指定的代码加上对 Base.Finalize() 的调用 .我会承认有些困惑,为什么 C# 会竭尽全力不允许人们简单地覆盖 Finalize() 或调用 Base.Finalize()。
      【解决方案4】:

      第二种意见更正确。您无法确保对象的析构函数将在指定时间运行。所以它不是析构函数,就像在 C++ 中那样,你可以显式调用 delete obj

      在 .NET 中,对于需要在使用后清理某些资源的对象,您应该实现 IDisposable 并在使用完对象或使用 using() 块时显式调用 Dispose。

      【讨论】:

        【解决方案5】:

        确定性意味着您可以在任何给定时间释放内存。这在 C# 中是不可能的,因为析构函数是由 GC 通过终结器线程在不确定的时间点调用的。

        【讨论】:

          【解决方案6】:

          我认为这只是术语不同的情况。单词在不同文本中的定义/使用方式不同 - 一直在发生。

          但是,如果您依赖垃圾收集器,则没有“确定性调用的清理”。你的结论:

          所以我看不出确定性调用的清理和垃圾收集器的情况有什么区别。

          ... 在您给出的上下文中没有意义。不同之处在于,一个是确定性调用的,另一个不是。

          【讨论】:

            猜你喜欢
            • 2011-04-22
            • 1970-01-01
            • 2016-03-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-01-31
            • 1970-01-01
            • 2011-08-22
            相关资源
            最近更新 更多