c#托管资源和非托管资源区别
public class BaseResource: IDisposable{// Pointer to an external unmanaged resource.// 非托管资源private IntPtr handle;// Other managed resource this class uses.// 托管资源private Component Components;// Track whether Dispose has been called.// 是否已经释放资源的标志private bool disposed = false;// Constructor for the BaseResource object.public BaseResource(){ // Insert appropriate constructor code here.}// Implement IDisposable.// Do not make this method virtual.// A derived class should not be able to override this method.// 提供给外部用户显示调用的方法,实际操作是在类的带参数的虚函数Dispose(bool disposing)中实现public void Dispose(){ // 表示用户显示调用 Dispose(true); // Take yourself off the Finalization queue // to prevent finalization code for this object // from executing a second time. // 由于用户是显示调用,所以资源释放不再由GC来完成 GC.SuppressFinalize(this);}// Dispose(bool disposing) executes in two distinct scenarios.// If disposing equals true, the method has been called directly// or indirectly by a user's code. Managed and unmanaged resources// can be disposed.// If disposing equals false, the method has been called by the// runtime from inside the finalizer and you should not reference// other objects. Only unmanaged resources can be disposed.protected virtual void Dispose(bool disposing){ // Check to see if Dispose has already been called. // 如果已经释放,不做再次的操作,出现在用户多次调用的情况下 if(!this.disposed) { // If disposing equals true, dispose all managed // and unmanaged resources. if(disposing) { // Dispose managed resources. // 用户是显示调用的话,我们就要手工的操作托管资源 Components.Dispose(); } // Release unmanaged resources. If disposing is false, // only the following code is executed. CloseHandle(handle); handle = IntPtr.Zero; // Note that this is not thread safe. // Another thread could start disposing the object // after the managed resources are disposed, // but before the disposed flag is set to true. // If thread safety is necessary, it must be // implemented by the client. } disposed = true; }// Use C# destructor syntax for finalization code.// This destructor will run only if the Dispose method// does not get called.// It gives your base class the opportunity to finalize.// Do not provide destructors in types derived from this class.// 析构函数~BaseResource() { // Do not re-create Dispose clean-up code here. // Calling Dispose(false) is optimal in terms of // readability and maintainability. // 表示本次调用是隐式调用,由Finalize方法调用,即托管资源释放由GC来完成 Dispose(false);}// Allow your Dispose method to be called multiple times,// but throw an exception if the object has been disposed.// Whenever you do something with this class,// check to see if it has been disposed.public void DoSomething(){ if(this.disposed) { throw new ObjectDisposedException(); }}}// Design pattern for a derived class.// Note that this derived class inherently implements the// IDisposable interface because it is implemented in the base class.public class MyResourceWrapper: BaseResource{// A managed resource that you add in this derived class.private ManagedResource addedManaged;// A native unmanaged resource that you add in this derived class.private NativeResource addedNative;private bool disposed = false;// Constructor for this object.public MyResourceWrapper(){ // Insert appropriate constructor code here.} // 重写Dispose方法,释放派生类自己的资源,并且调用基类的Dispose方法protected override void Dispose(bool disposing){ if(!this.disposed) { try { if(disposing) { // Release the managed resources you added in // this derived class here. addedManaged.Dispose(); } // Release the native unmanaged resources you added // in this derived class here. CloseHandle(addedNative); this.disposed = true; } finally { // Call Dispose on your base class. base.Dispose(disposing); } }}}// 在这里,派生类没有实现~MyResourceWrapper和public Dispose方法,应为他们已经继承了基类的这些特性,这也是我说本示例代码精要之处,他使用到了多态性原理,下面我会简单分析// This derived class does not have a Finalize method// or a Dispose method without parameters because it inherits// them from the base class.
?
本示例中有两个类一个是基类BaseResource,一个是派生类MyResourceWrapper,首先我们必须理解一下几点:
1.类型的?Dispose?方法应该释放它拥有的所有资源。它还应该通过调用其父类型的?Dispose?方法释放其基类型拥有的所有资源。该父类型的Dispose?方法应该释放它拥有的所有资源并同样也调用其父类型的?Dispose?方法,从而在整个基类型层次结构中传播该模式。
2.如果显式的调用了Dispose方法,我们就在Dispose方法中实现托管资源和非托管资源的释放,使用?GC.SuppressFinalize?方法来停止Finalize方法。因为如果用户调用了Dispose方法,那么我们就不必隐式的完成资源的释放,应为Finalizes会大大的减损性能。(Finalize一般只用于用户没有显式的调用Dispose方法,需要我们隐式完成时才使用)
3.要确保始终正确地清理资源,Dispose?方法应该可以被多次调用而不引发任何异常
示例中最主要的一个方法就是带参数的Dispose方法,本例中所有的具体操作都是放到这里来做的,它是一个受保护的虚函数,可以被派生类重写,并且如果派生类自己有对非托管资源的调用,那么派生类就要按照上面提到的要求,首先释放自己的资源,然后调用base.Dispose来实现基类的资源释放。(juky_huang注:这就是我们所谓的传播特性)
带参数的Dispose方法通过所带的参数disposing来判断,本次的Dispose操作是由Finalize发起还是由用户显式的调用公共Dispose方法发起的。如果为true则表示由公共的Dispose方法发起,如果为false表示是在GC调用Finalize方法时候发起。所以当为true时,我们就需要释放托管资源和非托管资源,并且禁止GC的Finalize操作,因为用户可以直接通过显示调用来减小性能开销。如果为false时,表示我们只需要释放非托管资源,因为本次调用是由GC的Finalize引起的,所以托管资源的释放可以让GC来完成。
示例中还有一个值得注意的地方,就是在多次显示调用Dispose时,如果资源已经处置,那么我们就要忽略本次操作,而不抛出异常。这个特性由disposed来决定。
好了,现在我们来看看这个程序的一个精要之处,那就是在派生类中,没有公共的Dispose方法,和Finalize方法(就是析构函数),那如果我们调用派生类对象时,是怎么实现资源释放的呢,刚开始我也不是很了解,后来仔细一看,突然发现其实很简单,它使用到了类的多态性来完成。
因为在派生类中使用了方法重写,所以在派生类中的Dispose(bool disposing)方法的派生度最大。由于基类中的Finalize和公共Dispose方法都是调用的是Dispose(bool disposing)方法,所以最终调用的是派生度最大的哪个函数,也就派生类中的Finalize和公共Dispose方法都是调用派生类自己的Dispose(bool disposing)方法。对于虚拟方法,可以参看我写的一篇文章地址是:
http://blog.csdn.net/juky_huang/archive/2005/10/26/517069.aspx
例如,现在我们有一个派生类实例A,如果我们显示调用A.Dispose()方法,它会去调用基础中的public Dispose方法这是由于继承的原因,在public Dispose方法中调用的又是Dispose(bool disposing)方法,由于这个方法已经被重写,所以它实际调用的不是基类中的Dispose(bool?disposing)方法,而是A自己的Dispose(bool disposing)方法。这是根据运行时类型来定的。所以最终还是实现了,先调用A中的资源释放,然后才调用base.Dispose方法来完成基类的资源释放。
如果用户没有显示调用Dispose方法,那么Finalize方法就会有效,过程和上面是类似的。
从上面可以看出,对于非托管资源的释放,有一个很好的规则,只要我们按照这个规则来做,你写的代码就是.Net中的“良民”。
?