Disposable.cs
103 lines
| 4.2 KiB
| text/x-csharp
|
CSharpLexer
/ Implab / Disposable.cs
|
|
r48 | using Implab.Diagnostics; | |
| using System; | |||
|
|
r100 | using System.Threading; | |
| using System.IO; | |||
|
|
r40 | ||
| namespace Implab { | |||
|
|
r48 | /// <summary> | |
| /// Объект, поддерживающий освобождение ресурсов. | |||
| /// </summary> | |||
|
|
r40 | public class Disposable : IDisposable { | |
|
|
r100 | int m_disposed; | |
|
|
r40 | ||
| public event EventHandler Disposed; | |||
| public bool IsDisposed { | |||
|
|
r100 | get { | |
| Thread.MemoryBarrier(); | |||
| return m_disposed != 0; | |||
| } | |||
|
|
r40 | } | |
|
|
r100 | /// <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> | |||
|
|
r40 | protected void AssertNotDisposed() { | |
|
|
r100 | Thread.MemoryBarrier(); | |
| if (m_disposed != 0) | |||
| throw new ObjectDisposedException(ToString()); | |||
|
|
r40 | } | |
|
|
r48 | /// <summary> | |
|
|
r100 | /// Вызывает событие <see cref="Disposed"/> | |
|
|
r48 | /// </summary> | |
| /// <param name="disposing">Признак того, что нужно освободить ресурсы, иначе данный метод | |||
| /// вызван сборщиком мусора и нужно освобождать ТОЛЬКО неуправляемые ресурсы ТОЛЬКО этого | |||
| /// объекта.</param> | |||
| /// <remarks> | |||
|
|
r100 | /// Данный метод вызывается гарантированно один раз даже при одновременном вызове <see cref="Dispose()"/> | |
| /// из нескольких потоков. | |||
|
|
r48 | /// </remarks> | |
|
|
r40 | protected virtual void Dispose(bool disposing) { | |
|
|
r100 | if (disposing) { | |
|
|
r40 | EventHandler temp = Disposed; | |
|
|
r100 | if (temp != null) | |
| temp(this, EventArgs.Empty); | |||
|
|
r40 | } | |
| } | |||
|
|
r100 | ||
|
|
r40 | public void Dispose() { | |
|
|
r100 | if (Interlocked.Increment(ref m_disposed) == 1) { | |
| Dispose(true); | |||
| GC.SuppressFinalize(this); | |||
| } | |||
|
|
r40 | } | |
|
|
r48 | /// <summary> | |
| /// Записывает сообщение об утечке объекта. | |||
| /// </summary> | |||
|
|
r40 | protected virtual void ReportObjectLeaks() { | |
|
|
r48 | TraceLog.TraceWarning("The object is marked as disposable but isn't disposed properly: {0}", this); | |
|
|
r40 | } | |
| ~Disposable() { | |||
| Dispose(false); | |||
| ReportObjectLeaks(); | |||
| } | |||
| } | |||
| } |
