c# - Java 和 C# 的终结器

标签 c# java garbage-collection finalizer finalize

Java

在 Java 中,有一个成语叫做“Finalizer Guardian”,它可以防止子类覆盖父类(super class)的终结器但忘记调用它。以下是来自 Effective Java Item7 的示例:

// Finalizer Guardian idiom
public class Foo {
  // Sole purpose of this object is to finalize outer Foo object
  private final Object finalizerGuardian = new Object() {
    @Override protected void finalize() throws Throwable {
      ... // Finalize outer Foo object
    }
  };
  ... // Remainder omitted
}

使用这种技术,即使具有终结器的子类不调用父类(super class)的终结器,私有(private)对象也会运行父类(super class)的终结代码。


C#

但是,在 C# in a Nutshell 的“从终结器调用 Dispose”部分,有一个这样的示例:

class Test : IDisposable {
  public void Dispose() // NOT virtual {
    Dispose (true);
    GC.SuppressFinalize (this); // Prevent finalizer from running.
  }

  protected virtual void Dispose (bool disposing) {
    if (disposing) {
      // Call Dispose() on other objects owned by this instance.
      // You can reference other finalizable objects here.
      // ...
    }
    // Release unmanaged resources owned by (just) this object.
    // ...
  }

  ˜Test() {
    Dispose (false);
  }
} 

作者还表示:

The disposing flag means it’s being called “properly” from the Dispose method rather than in “last-resort mode” from the finalizer. The idea is that when called with disposing set to false, this method should not, in general, reference other objects with finalizers (because such objects may themselves have been finalized and so be in an unpredictable state)


问题

但是,当我们回顾 Java 的 Finalizer Guardian 习语时,内部私有(private)守护对象实际上引用/终结了外部对象,而外部对象本身可能有一个终结器。 它违反了C# in a Nutshell 作者的声明。

我很好奇为什么“在终结器中引用其他可终结对象”在 Java 中可行,但在 C# 中不行。 感谢您的回答。

最佳答案

首先,在 C# 中,不能“忘记”在派生类中调用基类终结器,因为没有语法可以重写基类终结器——它将始终被调用(类似于构造函数)。

确实可以覆盖 Dispose 而忘记调用基类的版本——在这种情况下,将跳过基类中完成的实现。另一方面,如果派生类忘记处理父类,在 C# 中正确实现可终结类不会导致致命问题 - 真正管理 native 资源(如 OS 句柄)的类应该被密封,从而避免出现问题(因为可以'在这种情况下重写任何方法)。

下半年关于完成订单:

我不知道 Java 终结化如何或是否保证对象以一致的顺序终结,因此所有引用在所有终结器完成之前都是有效的...

在 .Net/C# 中,终结器的顺序是未定义的——这意味着在确定了哪些对象需要被终结之后(由于缺少外部引用),该集合中的对象将在没有任何特定顺序的情况下被调用终结器。结果是,如果集合中的对象相互引用,而不是调用最后一个对象的终结器时,所有其他对象都已经完成。

关于c# - Java 和 C# 的终结器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21771043/

相关文章:

java - 在非常耦合的业务逻辑中解耦 Java 中的类

java - 同一变量中类的多个实例化

c# - 如何使用 C# 在文本中查找重复出现的词组?

c# - 关于使用 ADO.Net 数据服务,我应该了解什么? (常问问题)

c# - 如何只处理某些 XML 节点?

c# - 如何检测 ToolStripTextBox 中的 Alt + 左键

java - 错误: org. hibernate.PropertyNotFoundException : no appropriate constructor in class: com. a.offering.dto.SellerDetailsDto

java - 如何自动检测和连接从特定类型扩展的类?

hadoop - 如何为 Hadoop YARN ResourceManager 和 ApplicationTimeline 启用 GC 日志记录,同时防止日志文件覆盖和限制磁盘空间使用

java - Linux 使用运行 Java GC 的系统/内核 CPU