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
    }
Rating: