1

我们有构造函数,我们可以将它们视为对象实例化的合约。

如果不向构造函数提供精确的参数集,就没有其他方法可以创建实例。

但是我们如何(并且我们应该打扰)执行一些验尸活动?我们有终结器,但不建议将它们用于通用终结器。我们也必须IDisposable实施。但是,如果我们在没有一次性对象的情况下使用,using我们无法保证 Dispose 会被调用。

为什么现在有办法在对象被释放之前强制执行对象的某些状态?

在终结器中整理是不可能的,因为不能保证对象图是完整的,并且垂死对象的引用对象没有被 GC 清空。

当然,不SaveState()通过客户端代码调用实例对象会给它带来一些麻烦,而不是我的对象。

尽管如此,要求在构造函数中注入所有需要的依赖项被认为是一种好习惯(如果没有可用的默认值)。没有人会轻易说:“离开默认构造函数,创建属性并在对象处于无效状态时抛出异常。”

更新:

由于有很多投票可以结束这个问题,我想说一些设计模式也可以作为答案。

无论您是否使用 DI,您都可以计算对象被请求/创建的次数。但是如果没有明确的释放调用,你不知道什么时候应该调用 dispose。

我根本不明白如何在正确的时间实施处置。

4

2 回答 2

12

为什么在对象被释放之前没有办法强制执行对象的某些状态?

因为垃圾收集器的全部意义在于模拟具有无限内存的机器。如果内存是无限的,那么你永远不需要清理它。

您将程序的语义要求(在特定时间发生特定副作用)与模拟无限存储的机制混为一谈。在理想的世界中,这两件事不应该相互关联。不幸的是,我们不是生活在一个理想的世界里。终结器的存在就是证明。

如果您想在特定时间实现某些效果,那么这些效果就是您的程序的一部分,您应该编写实现它们的代码。如果它们很重要,那么它们应该在代码中可见,以便阅读代码的人可以看到并理解它们。

于 2013-04-18T17:36:27.527 回答
2

不幸的是,在 Java 的设计过程中,预期垃圾收集器应该能够满足所有清理要求。在 .NET 的早期设计阶段,这似乎也是一种信念。

因此,没有区别:

  • 封装了object reference其目标的专有所有权;

  • areference to an object不封装所有权(其目标由其他人拥有)

  • areference whose owner知道它将封装独占所有权封装 none,并且知道哪种情况适用于手头的实例;

  • object reference封装共享所有权的。

如果围绕这些区别正确设计了一种语言和框架,则很少需要编写无法静态验证正确清理的代码(前两种情况可能适用于 90% 以上的时间,即使使用 .NET 框架)。

不幸的是,因为在非常有限的语句上下文之外不存在这样的区别using,所以编译器或验证器无法知道,当一段代码放弃引用时,是否有其他任何东西期望清理由此引用的对象。

因此,一般无法知道该对象是否应该被处置,也没有普遍意义的方式来发出尖叫,如果它应该被处置但不是。

于 2013-04-18T17:52:51.197 回答