在具有Finalizer

时间:2016-01-21 09:38:53

标签: c# dispose finalizer

根据Essential C# 6.0你应该:

  

AVOID在拥有终结器的拥有对象上调用Dispose()。   相反,依靠终结队列来清理实例。

  1. 有人可以详细说明这一点,因为如果我们不从拥有的对象中调用它,我不清楚Dispose的意义是什么吗?
  2. 除了Reflection之外,您如何判断对象是否有Finalizer
  3. 除了搜索API文档(如果您有权访问它并且存在)或反射之外,您如何确定何时拨打Close() / Close() + Dispose()?对于非常具体的类型(MemoryStream / Form / SqlConnection /等),我在网络上看到了很多问题,但我更关注"如何计算你自己"。
  4. 根据Dispose Pattern你应该:

      

    CONSIDER提供方法Close(),除了Dispose()之外,如果close是该区域的标准术语。这样做时,将Close实现与Dispose相同并考虑显式实现IDisposable.Dispose方法非常重要。

    但有时你应该像Form一样打电话,等等问题,例如" Close and Dispose - which to call?"接近但除了

    之外没有明确的方法
      

    通常答案是:这取决于。不同的类以不同的方式实现IDisposable,并且由您来进行必要的研究。

    编辑:这是完整的指南,我还没有要求获得许可,但因为它是一个指南(从而假设它应该是自由共享的公共知识)而不是某些部分实际的培训材料,我希望我不违反任何规则。

      

    指南
      即使最终化延迟了垃圾收集,也只对资源稀缺或昂贵的对象实施终结器方法   实现IDisposable以支持具有终结器的类的确定性终结   如果没有明确调用Dispose(),请对实现IDisposable的类实现终结器方法   DO重构一个finalization方法来调用与IDisposable相同的代码,也许只是调用Dispose()方法。
      不要从终结器方法中抛出异常   从Dispose()调用System.GC.SuppressFinalize()以避免重复资源清理并延迟对象上的垃圾回收。
      确保Dispose()是幂等的(应该可以多次调用Dispose())   保持Dispose()简单,专注于最终确定所需的资源清理   AVOID在拥有终结器的拥有对象上调用Dispose()。相反,依靠终结队列来清理实例   避免在最终确定期间引用尚未最终确定的其他对象   在重写Dispose()时,请调用基类的Dispose()方法   在调用Dispose()之后,考虑确保对象变得不可用。在处理了一个对象之后,Dispose()以外的方法(可能多次被调用)应抛出一个ObjectDisposedException。
      在具有一次性字段(或属性)的类型上实现IDisposable并处理所述实例。

1 个答案:

答案 0 :(得分:6)

  
      
  1. 有人可以详细说明这一点,因为我不清楚Dispose的重点是什么,如果我们不从拥有的对象中调用它?
  2.   

如果没有书的全文及其背景(我没有书的副本,也没有其他人阅读你的问题),就不可能肯定地说出他们的意思。但它本来应该是一本好书,因此我必须假设您引用的文本仅适用于 到您自己的终结器中的代码。即当然你应该正常处置拥有的对象。在Dispose()方法中。

如果对象没有正确处理,该怎么办?答案就是清理你自己的非托管资源。

与此相关的是,现在,随着SafeHandle类的出现(不久前),您可能根本不需要终结器。相反,将您自己的非托管资源包装在SafeHandle子类中,让该类处理完成。

  
      
  1. 除了Reflection,你会如何判断对象是否有Finalizer?
  2.   

除了反思之外,您将依赖源代码(如果可用),文档(如果编写),或者仅仅是对象实现IDisposable的事实(即做出假设......它不能保证,但两者之间存在很强的相关性。

更重要的是,请注意,因为可以在不使用终结器的情况下正确实现实现IDisposable的对象(例如,如果您使用SafeHandle,或者实施IDisposable只有这样才能确定性地清理拥有的IDisposable个对象),不能保证终结器的存在。

我认为更好的指导方法是“不要在终结器中处理对象”。依赖于IDisposable对象本身以某种方式处理最终自己拥有的资源的事实,并且只关注您自己的对象拥有的任何非托管资源直接

  
      
  1. 除了搜索API文档(如果您有权访问它并且存在)或反射之外,您如何知道何时调用Close()/ Close()+ Dispose()?对于非常特定的类型(MemoryStream / Form / SqlConnection / etc),我在网络上看到很多问题,但我更关注“如何自己解决”。
  2.   

你做不到。并非没有仔细检查代码。那说......

您永远不必同时拨打Close()Dispose()。如果正确实现了类,则两者应始终等效。

当然,.NET中没有强制执行的内容。因此,不可能肯定地说你不需要。但是如果你正在处理一种既需要两者的类型,那么它写得很差,也可能在其他方面被打破。最好完全避免完全使用该类型。 :)

当然,正如您所指出的,Form在某些情况下要求您同时调用Close()Dispose()(在大多数情况下,调用Close()实际上已经足够......只是因为他们实现了模态对话框的奇怪方式,你得到规则的例外)。但这是一个非常古老的API,在IDisposable模式的复杂性的全部含义被真正完全理解之前设计。人们希望,如果不得不再次这样做,微软就不会以同样的方式设计该API(实际上,WPF没有相同的二分法)。

现代实施应该更好地更好地遵循良好的约定。


附录:

我做了一点浏览。当然,在Stack Overflow上有很多关于GC,finalization,IDisposable,终结器等的文章,但我没有看到任何与你的问题直接相同的文章。这个似乎是最接近的:

Which objects can I use in a finalizer method?

其他可能有用的额外阅读:

When would dispose method not get called?
Why call Dispose()? Memory leak won't occur?
IDisposable and managed resources

当然,经典:
Proper use of the IDisposable interface