利用c#实现标准的 dispose模式_c#应用

2008-02-23 05:44:42来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折

  本文讲解的是您在建立包含内存以外资源的类型,特别是处置非内存资源的时候,如何编写自己的资源管理代码。

  我们已知道了处置那些占用非受控(unmanaged)资源的对象的重要性,现在应该编写资源管理代码来处置那些包含非内存资源的类型了。整个.NET框架组件都使用一个标准的模式来处理非内存资源。使用您建立的类型的用户也希望您遵循这个标准的模式。标准的处理模式的思想是这样的:当客户端记得的时候使用IDisposable接口释放您的非受控资源,当客户端忘记的时候防护性地使用终结器(finalizer)。他和垃圾收集器(Garbage Collector)一起工作,确保只在必要的时候该对象才受到和终结器相关的性能影响。这是处理非受控资源的一条很好的途径,因此我们应该完全地认识他。

  类层次体系中的根基类(root base class)必须实现IDisposable接口以释放资源。这个类型还必须添加一个作为防御机制的终结器。任何这些程式都把释放资源的工作委托给一个虚拟的方法,衍生的类能够根据自己的资源管理需求来重载该方法。只要衍生的类必须释放自己的资源,并且他必须调用该函数的基类版本的时候,他才需要重载这个虚拟方法。

  开始的时候,假如您的类使用了非内存资源,他就必须含有一个终结器。您不能依赖客户端总是调用Dispose()方法。因为当他们忘记这样做的时候,您就面临资源泄漏的问题。没有调用Dispose是他们的问题,但是您却有过失。用于确保非内存资源被正确地释放的唯一途径是建立终结器。

  当垃圾收集器运行的时候,他立即从内存中删除任何不带终结器的垃圾对象。任何带有终结器的对象仍然存在于内存中。这些对象都被添加到终结队列,垃圾收集器引发一个新线程,周期性地在这些对象上运行终结器。在这些终结程式线程完成自己的工作之后,就能够从内存中删除垃圾对象了。需要终结的对象在内存中停留的时间比没有终结器的对象停留的时间长很多。但是您别无选择。假如要使程式有防护性,在类型包含非受控资源的时候,您必须编写一个终结器。但是也不用担心性能问题。下一步确保了客户端避免和终结相关的性能开销。
实现IDisposable接口是一种标准的途径,他通知用户和运行时系统持有资源的对象必须及时地释放。IDisposable接口仅仅包含一个方法:

public interface IDisposable
{
 void Dispose( );
}

  您对IDisposable.Dispose()方法的实现(implementation)负责下面四个事务:

  1、释放任何的非受控资源。

  2、释放任何的受控资源(包括未解开事件)。

  3、配置标志表明该对象已被处理过了。您必须在自己的公共方法中检查这种状态标志并抛出ObjectDisposed异常(假如某个对象被处理过之后再次被调用的话)。

  4、禁止终结操作(finalization)。您调用GC.SuppressFinalize(this)来完成这种事务。

  通过实现IDisposable接口您完成了两个事务:您为客户端及时地释放自己持有的任何受控资源提供了机制;您为客户端提供了一种释放非受控资源的标准途径。这是个很大的进步。当您在类型中实现了Idisposable接口的时候,客户端能够避免终结操作的开销,您的类就成为.NET世界中的"良民"了。

  但是在您建立的这种机制中仍然存在一些问题。怎样在衍生类清理自己资源的时候同时也让基类能够清理资源?假如衍生类重载了终结操作,或添加了自己的IDisposable实现,那么这些方法必须调用基类,否则,基类就不能正确地进行清理操作。同样,finalize(终结操作)和Dispose参和分担了一些相同的职责。Finalize方法和Dispose方法的代码几乎相同。而且在重载接口函数后并不像您预料的那样工作。标准的Dispose模式中的第三个方法是个受保护的虚拟辅助函数,他分解出这些一起的事务,并给衍生类添加一个用于释放资源的"钩子(hook)"。基类包含了核心接口的代码。作为对Dispose()或终结操作的响应,该虚拟函数为衍生类清除资源提供了"钩子":

protected virtual void Dispose( bool isDisposing );

  这个重载的方法实现支持finalize和Dispose的必要事务,由于他是虚拟的,他为任何的衍生类提供了一个入口点。衍生类能够重载这个方法,为清除自己的资源提供适当的实现,同时还能够调用基类版本。当isDisposing为真(true)的时候,您能够清除受控和非受控资源,当isDisposing为假(false)的时候,您只能清除非受控资源。在这两种情况下,您都能够调用基类的Dispose(bool)方法,让他清除自己的资源。

  下面有一个简短的例子,他演示了您在实现这种模式的时候所提供的代码框架。MyResourceHog类演示了实现IDisposable接口、终结器的代码,并建立了一个虚拟的Dispose方法:

public class MyResourceHog : IDisposable
{
 // 已被处理过的标记
 private bool _alreadyDisposed = false;
 // 终结器。调用虚拟的Dispose方法
 ~MyResourceHog()
 {
  Dispose( false );
 }

 // IDisposable的实现
 // 调用虚拟的Dispose方法。禁止Finalization(终结操作)
 public void Dispose()
 {
  Dispose( true );
  GC.SuppressFinalize( true );
 }

 // 虚拟的Dispose方法
 protected virtual void Dispose( bool isDisposing )
 {
  // 不要多次处理
  if ( _alreadyDisposed )
   return;
  if ( isDisposing )
  {
   // TODO: 此处释放受控资源
  }
  // TODO: 此处释放非受控资源。配置被处理过标记
  _alreadyDisposed = true;
 }
}

  假如衍生类需要执行另外的清除操作,他应该实现受保护的Dispose方法:

public class DerivedResourceHog : MyResourceHog
{
 // 他有自己的被处理过标记
 private bool _disposed = false;

 protected override void Dispose( bool isDisposing )
 {
  // 不要多次处理
  if ( _disposed )
   return;
  if ( isDisposing )
  {
   // TODO: 此处释放受控资源
  }
  // TODO: 此处释放任何受控资源
 
  // 让基类释放自己的资源。基类负责调用GC.SuppressFinalize( )

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇: 使用c#编写一个计时器_c#应用

下一篇: 如何用c#将数据库中的记录制成xml_c#应用