//----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. // //----------------------------------------------------------------------- namespace Microsoft.Isam.Esent.Interop { using System; using System.Diagnostics; /// /// This is the base class for all esent resource objects. /// Subclasses of this class can allocate and release unmanaged /// resources. /// public abstract class EsentResource : IDisposable { /// /// True if a resource has been allocated. /// private bool hasResource; /// /// True if this object has been disposed. /// private bool isDisposed; /// /// Finalizes an instance of the EsentResource class. /// ~EsentResource() { this.Dispose(false); } /// /// Gets a value indicating whether the underlying resource /// is currently allocated. /// protected bool HasResource { get { return this.hasResource; } } /// /// Dispose of this object, releasing the underlying /// Esent resource. /// public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } /// /// Called by Dispose and the finalizer. /// /// /// True if called from Dispose. /// protected virtual void Dispose(bool isDisposing) { if (isDisposing) { if (this.hasResource) { this.ReleaseResource(); Debug.Assert(!this.hasResource, "Resource was not freed"); } this.isDisposed = true; } else { if (this.hasResource) { // We should not get to this point. The problem is that if // we use finalizers to free esent resources they may end // up being freed in the wrong order (e.g. JetEndSession is // called before JetCloseTable). Freeing esent resources // in the wrong order will generate EsentExceptions. Trace.TraceWarning("Non-finalized ESENT resource {0}", this); } } } /// /// Throw an exception if this object has been disposed. /// protected void CheckObjectIsNotDisposed() { if (this.isDisposed) { throw new ObjectDisposedException("EsentResource"); } } /// /// Called by a subclass when a resource is allocated. /// protected void ResourceWasAllocated() { this.CheckObjectIsNotDisposed(); Debug.Assert(!this.hasResource, "Resource is already allocated"); this.hasResource = true; } /// /// Called by a subclass when a resource is freed. /// protected void ResourceWasReleased() { Debug.Assert(this.hasResource, "Resource is not allocated"); this.CheckObjectIsNotDisposed(); this.hasResource = false; } /// /// Implemented by the subclass to release a resource. /// protected abstract void ReleaseResource(); } }