C#中标准Dispose模式的实现与使用(条目17 实现标准的销毁模式)
2013-11-28 11:04 咒语 阅读(1156) 评论(0) 编辑 收藏 举报实现了Dispose模式与实现了IDisposable接口的区别就是:IDisposable的实现的可靠性(释放相关资源)要靠编程人员来解决(你确信你从来都一直调用了Dispose(Close)方法吗?),而实现了Dispose模式后,当编程人员没有主动调用Dispose方法时,会由终结器来调用(有些时候编程人员想主动调用也调用不了,比如远程连上来的TcpChannel,客户端断开时,服务端只能由终者器调用)。
Dispose模式()的实现需要以下4个步骤:
1. 释放所有非托管资源;
2. 释放所有托管资源,包括释放事件监听程序;
3. 设计一个状态标志(IsDisposed),表示该对像已经被销毁。若是在销毁后再次调用对像的公有方法,那么应该抛出ObjectDisposed异常;
4. 跳过终者操作,调用CG.SuppressFinalize(this)即可。
注:
------------------
托管资源:由CLR管理分配和释放的资源,即由CLR里new出来的对象;
非托管资源:不受CLR管理的对象,windows内核对象,如文件、数据库连接、套接字、COM对象等;
用实现来说明。
EXAMPLE CODE:
using System; namespace CS.DesignPatterns { /// <summary> /// 示例 /// </summary> public class DisposePatternSample:IDisposable { private bool _isDisposed;//是否已释放了资源,true时方法都不可用了。 public DisposePatternSample() { _isDisposed = false; } public void MethodSample() { if(_isDisposed) throw new ObjectDisposedException("inner resource is disposed."); Console.WriteLine("MethodSample is called."); } /// <summary> /// 为继承类释放时使用 /// <remarks> /// Note:这儿为什么要写成虚方法呢? /// 1. 为了让派生类清理自已的资源。将销毁和析构的共同工作提取出来,并让派生类也可以释放其自已分配的资源。 /// 2. 为派生类提供了根据Dispose()或终结器的需要进行资源清理的必要入口。 /// </remarks> /// </summary> /// <param name="isDisposing"></param> protected virtual void Dispose(bool isDisposing) { if(_isDisposed)return; if (isDisposing) { //释放托管资源 //(由CLR管理分配和释放的资源,即由CLR里new出来的对象) //TODO: other code } //释放非托管资源 //(不受CLR管理的对象,windows内核对象,如文件、数据库连接、套接字、COM对象等) //TODO: other code _isDisposed = true; } #region IDisposable 成员 public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } #endregion ///// <summary> ///// 如果没有非托管资源,不要实现它 ///// </summary> //~DisposePatternSample() //{ // Dispose(false); //} } public class DrivedDisposePatternSample : DisposePatternSample { private bool _isDisposed = false; //各类维护自已的释放状态,把可能出现的错误限制在类本身 /// <summary> /// 子类清理自已的资源时使用 /// </summary> /// <param name="isDisposing"></param> protected override void Dispose(bool isDisposing) { if(_isDisposed)return; if (isDisposing) { //释放托管资源 //(由CLR管理分配和释放的资源,即由CLR里new出来的对象) //TODO: other code } //释放非托管资源 //(不受CLR管理的对象,windows内核对象,如文件、数据库连接、套接字、COM对象等) //TODO: other code //基类释放资源 //基类负责调用GC.SuppressFinalize() base.Dispose(isDisposing); _isDisposed = true; } ///// <summary> ///// 如果没有非托管资源,不要实现它 ///// </summary> //~DrivedDisposePatternSample() //{ // Dispose(false); //} } }
上述的代码并没有使用析构方法,这是因为上述的代码并没有使有非托管资源(永远不会调用Dispose(false))方法。注意:除非你调用了非托管资源,否则不要实现析构方法。即使析构器永远不会被调用,它本身也会极大的影响类型的性能。不要画蛇添足。不过这个模式却不能改变,因为你的派生类可能会用到非托管的资源。
重要的建议:只能在Dispose方法中释放资源,不得进行其它操作(如果一不小心的其它操作,让本该死亡的对象起死回生,哼哼~~~~)。
请遵守Dispose标准模式的实现,这会节省你,你的类型使用者,你的类型的派生者的大量的时间。