view Implab/Components/Disposable.cs @ 187:dd4a3590f9c6 ref20160224

Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler Any unhandled OperationCanceledException will cause the promise cancelation
author cin
date Tue, 19 Apr 2016 17:35:20 +0300
parents 240aa6994018
children 7d07503621fe
line wrap: on
line source

using Implab.Diagnostics;
using System;
using System.Threading;

namespace Implab.Components {
    /// <summary>
    /// Base class the objects which support disposing.
    /// </summary>
    public class Disposable : IDisposable {
        
        int m_disposed;

        public event EventHandler Disposed;

        public bool IsDisposed {
            get {
                Thread.MemoryBarrier();
                return m_disposed != 0;
            }
        }

        /// <summary>
        /// Asserts the object is not disposed.
        /// </summary>
        /// <exception cref="ObjectDisposedException">The object is disposed</exception>
        /// <remarks>
        /// Успешная проверка того, что объект не освобожден еще не гарантирует, что он не
        /// будет освобожден сразу после нее, поэтому методы использующие проверку должны
        /// учитывать, что объект может быть освобожден из параллельного потока.
        /// Данны метод служит для упрощения отладки ошибок при использовании объекта после его
        /// освобождения.
        /// </remarks>
        /// <example>
        /// // пример синхронизированного освобождения ресурсов
        /// class FileStore : Disposable {
        ///     readonly TextWriter m_file;
        ///     readonly obejct m_sync = new object();
        /// 
        ///     public FileStore(string file) {
        ///         m_file = new TextWriter(File.OpenWrite(file));
        ///     }
        /// 
        ///     public void Write(string text) {
        ///         lock(m_sync) {
        ///             AssertNotDisposed();
        ///             m_file.Write(text);
        ///         }
        ///     }
        /// 
        ///     protected override void Dispose(bool disposing) {
        ///         if (disposing)
        ///             lock(m_sync) {
        ///                 m_file.Dipose();
        ///                 base.Dispose(true);
        ///             }
        ///         else
        ///             base.Dispose(false);
        ///     }
        /// }
        /// <example> 
        protected void AssertNotDisposed() {
            Thread.MemoryBarrier();
            if (m_disposed != 0)
                throw new ObjectDisposedException(ToString());
        }
        /// <summary>
        /// Вызывает событие <see cref="Disposed"/>
        /// </summary>
        /// <param name="disposing">Признак того, что нужно освободить ресурсы, иначе данный метод
        /// вызван сборщиком мусора и нужно освобождать ТОЛЬКО неуправляемые ресурсы ТОЛЬКО этого
        /// объекта.</param>
        /// <remarks>
        /// Данный метод вызывается гарантированно один раз даже при одновременном вызове <see cref="Dispose()"/>
        /// из нескольких потоков.
        /// </remarks>
        protected virtual void Dispose(bool disposing) {
            if (disposing) {
                EventHandler temp = Disposed;
                if (temp != null)
                    temp(this, EventArgs.Empty);
            }
        }

        public void Dispose() {
            if (Interlocked.Increment(ref m_disposed) == 1) {
                Dispose(true);
                GC.SuppressFinalize(this);
            }
        }

        /// <summary>
        /// Записывает сообщение об утечке объекта.
        /// </summary>
        protected virtual void ReportObjectLeaks() {
            TraceLog.TraceWarning("The object is marked as disposable but isn't disposed properly: {0}", this);
        }

        ~Disposable() {
            Dispose(false);
            ReportObjectLeaks();
        }
    }
}