|
|
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) {
|
|
|
EventHandler temp = Disposed;
|
|
|
if (temp != null)
|
|
|
temp(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();
|
|
|
}
|
|
|
}
|
|
|
}
|