view Implab/Components/Disposable.cs @ 243:b1e0ffdf3451 v3

working on promises
author cin
date Wed, 24 Jan 2018 19:24:10 +0300
parents 9ee78a345738
children 9f63dade3a40
line wrap: on
line source

using Implab.Diagnostics;
using System;
using System.Diagnostics.CodeAnalysis;
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)
                Disposed.DispatchEvent(this, EventArgs.Empty);

        }

        [SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly", Justification = "Dipose(bool) and GC.SuppessFinalize are called")]
        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();
        }
    }
}