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 theDispose
method rather than in “last-resort mode” from the finalizer. The idea is that when called withdisposing
set tofalse
, 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/