实现了Dispose模式与实现了IDisposable接口的区别就是:IDisposable的实现的可靠性(释放相关资源)要靠编程人员来解决(你确信你从来都一直调用了Dispose(Close)方法吗?),而实现了Dispose模式后,当编程人员没有主动调用Dispose方法时,会由终结器来调用(有些时候编程人员想主动调用也调用不了,比如远程连上来的TcpChannel,客户端断开时,服务端只能由终者器调用)。
Dispose模式()的实现需要以下4个步骤:
- 释放所有非托管资源;
- 释放所有托管资源,包括释放事件监听程序;
- 设计一个状态标志(IsDisposed),表示该对像已经被销毁。若是在销毁后再次调用对像的公有方法,那么应该抛出ObjectDisposed异常;
- 跳过终者操作,调用CG.SuppressFinalize(this)即可。
注:
托管资源:由CLR管理分配和释放的资源,即由CLR里new出来的对象;
非托管资源:不受CLR管理的对象,windows内核对象,如文件、数据库连接、套接字、COM对象等;
用实现来说明
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标准模式的实现,这会节省你,你的类型使用者,你的类型的派生者的大量的时间。