C# IDisposable Interface Implementation
Long long time ago I dissected the IDisposable interface (simple enough as it is) and made a "correct" implementation example essentially by commenting out MSDN code for better understanding what for and why you should do as it says:
class DisposableExample: IDisposable { #region Absolute minimum of the code required for correct implementation of IDisposable ////// Field that will be set to true if attempt to destroy the object was already made. /// private bool isDisposed = false; ////// This method implements IDisposable. /// It is either called by the programmer explicitly or from using() block /// Microsoft says that this method should not be made virtual, but does not elaborate why. /// Most likely this is so the order of calls to Dispose()/GC.SuppressFinalize() is not messed up. /// public void Dispose() { //Calling the method's overload specifying that it was called explicitly: Dispose(true); //Cancelling destructor's call for this object — we already cleaned everything up. //This is not critical (because we have protection from double-calling of Dispose(bool) method — isDisposed flag), //but would help us to optimize performance. GC.SuppressFinalize(this); } ////// This is destructor otherwise known as finalizer. /// It's being called by the Garbage Collector when the framework decides that it's time to clean up. /// ~DisposableExample() { //Calling cleanup method specifying that it's called from the destructor. //If we have no unmanaged reseources, "supposedly" nothing new would happen //and there's not much sense in this call, but it's better to be safe than sorry. //We'll come here only if the developer forgets to destroy the object and did not call Dispose() Dispose(false); //Nothing else should be in the destructor — all resource cleanup code shoud more to Dispose(bool) } ////// Resource cleanup. /// This method is not virtual to keep the logic in the inherited classes, /// instead two methods DisposeManaged() and DisposeUnmanaged(), that are being called inside, are made virtual. /// /// /// True, if Dispose() method being called explicitly or from using() block /// False, when Dispose() method being called from destructor (during garbage collection). Do not use managed resources, the Garbage Collector will take care of them /// In the MSDN example this parameter called "disposing" that does not really describes its purpose. /// protected void Dispose(bool isCalledExplicitly) { //Checking that this method has not been already called: if(!isDisposed) { try { if(isCalledExplicitly) { //Dispose() was explicitly called by the programmer, //who wanted to free up memory, because this object will no longer be needed. //Garbage Collector hasn't yet dealed with our object, //therefore we release managed resources ourselves. DisposeManaged(); } //Releasing unmanaged resources, Garbage Collector will have no way of knowing about them, //that's why nobody but us will clean them up DisposeUnmanaged(); } finally { //To avoid repeated calls to this method: isDisposed = true; } } } ////// Releasing internal managed objects. /// May be overriden in derived classes with a call to base.DisposeManaged() /// If we are writing base class without any functionality here, /// this method should be declared abstract and not protected. /// protected virtual void DisposeManaged() { //We need to destroy all managed resources here //All internal properties implementing IDisposable will be processed in this method: //this.DisposableProperty.Dispose(); } ////// Freeing up internal unmanaged resources /// May be overriden in derived classes with a call to base.DisposeUnmanaged() /// If we are writing base class without any functionality here, /// this method should be declared abstract and not protected. /// protected virtual void DisposeUnmanaged() { //Here we clean up resources unknown to .Net Framework, //for instance, open file handles: //CloseHandle(handle); } #endregion #region Additional methods and properties that could be useful ////// Returns true if the object is already destroyed. /// Tells us that this object should no longer be used. /// protected bool IsDisposed { get { return isDisposed; } } ////// This method will raise exception if Dispose() was already called. /// CheckDisposed() may be inserted at the start of other methods, /// who care about object's integrity. /// protected void CheckDisposed() { if(IsDisposed) throw new ObjectDisposedException(null); } #endregion }
- Previous
- Next