IDisposable:关于资源销毁,老师不告诉你的事

本文翻译自IDisposable:What Your Mother Never Told You About Resource Deallocation

译者:爱让一切都对了

(有删简)

控制IDisposable

这篇文章的第一部分讨论了IDisposable接口的问题,这部分将着眼于实现IDisposable的“最佳做法”。

解决IDisposable的问题:用可销毁设计模式,少用IDisposable

微软推荐的IDisposable代码模式很复杂,因为他们试图用这一个模式实现所有可能的情况。

  • 对于每一个非托管资源,创建一个(可能是internalIDisposable包装类,负责释放这个非托管资源。微软在BCL(BasicClass Library)中遵循了这一原则。注意,包装了非托管资源的IDisposable类,应当认为是一种托管资源。

  • 不要从非托管资源的包装类继承。

  • 一个类拥有托管资源,或派生自拥有托管资源的类时,要实现IDisposable

  • 不要在一个类中同时考虑托管和非托管资源。

根据以上指导原则,可销毁设计原理应当是这样的:

  • 0级类型直接包装非托管资源。这些类型通常是密封的。

  • 1级类型是派生字1级类型,或包含有0级或1级类型的字段。

包装非托管资源的类,越靠近原生API越好。这些包装类应该很小,而且是私有的或内部的。包装类的唯一任务就是负责销毁非托管资源。其他功能要在1级类中实现。1级类的字段可能有0级类。总的来说,

0级类型只处理非托管资源;1级类型只处理(父类中的或字段中的)托管资源。

  • 在1级类型上实现IDisposable很简单:在IDisposable.Dispose里调用字段的Dispose方法,然后调用base.Dispose()。

  • Dispose可以多次调用。

  • 1级类型没有终结器。

  • 没必要调用GC.KeepAlive(this)

  • 调用GC.SuppressFinalize(this)也是不必要的。

话说回来,为0级类型实现IDisposable确实很困难。能不碰它就不要碰它。

解决IDisposable的问题:用辅助类

虽说不要碰0级类型,但确实常常要写的非托管资源包装类,比如说一些数据结构的指针。微软的System.Runtime.InteropServices.SafeHandleSystem.Runtime.InteropServices.CriticalHandleMicrosoft.Win32.SafeHandles会让你写起来简单一点。

0级类型应该始终继承自SafeHandleCriticalHandle,从名字上看起来就不那么安全,最好不要使用。

所以说写一个新的非托管资源的类包装有四种情况(从易到难):

  • 已经有一个0级的非托管资源的类型,SafeHandle的子类。这样的话,程序员仅需要创建一个新的1级类型。

  • 非托管资源是一个指针类型,但微软没帮我写好一个0级类型。这样的话,程序员需要创建两个类,一个0级类型和一个1级类型。

  • 要包装不仅有指针,还有其他一些数据。这样的话,程序员也是一个0级类型和一个1级类型。当然那个0级类型会比较复杂。

  • 非托管资源根本就不是指针。这样的话,程序员也是一个0级类型和一个1级类型。当然那个0级类型会比较复杂。

注意,从1级类型继承时,通常会是声明一个受保护的1级类型的属性,与其相关的字段一般0级类型有些关系。

你可能感兴趣的:(IDisposable:关于资源销毁,老师不告诉你的事)