A simple and totally thread-safe implementation of IDisposable
A simple and totally thread-safe implementation of IDisposable, with improved semantics over the Dispose() / Dispose(bool disposing) reference implementation. Now updated, slightly, after a consult with someone much smarter than me, who suggested a slight improvement: use Thread.VolatileRead in the IsUndisposed method.
Instructions:
Override DisposeResources in derived classes. When this method is called, always release unmanaged resources, and dispose of managed resources only if the disposeManagedResources parameter is true.
using System;
using System.Threading;
/// <summary>
/// DisposableBase class. Represents an implementation of the IDisposable interface.
/// </summary>
public abstract class DisposableBase : IDisposable
{
/// <summary>
/// A value which indicates the disposable state. 0 indicates undisposed, 1 indicates disposing
/// or disposed.
/// </summary>
private int disposableState;
/// <summary>
/// Finalizes an instance of the DisposableBase class.
/// </summary>
~DisposableBase()
{
// The destructor has been called as a result of finalization, indicating that the object
// was not disposed of using the Dispose() method. In this case, call the DisposeResources
// method with the disposeManagedResources flag set to false, indicating that derived classes
// may only release unmanaged resources.
this.DisposeResources(false);
}
/// <summary>
/// Gets a value indicating whether the object is undisposed.
/// </summary>
public bool IsUndisposed
{
get
{
return Thread.VolatileRead(ref this.disposableState) == 0;
}
}
#region IDisposable Members
/// <summary>
/// Performs application-defined tasks associated with disposing of resources.
/// </summary>
public void Dispose()
{
// Attempt to move the disposable state from 0 to 1. If successful, we can be assured that
// this thread is the first thread to do so, and can safely dispose of the object.
if (Interlocked.CompareExchange(ref this.disposableState, 1, 0) == 0)
{
// Call the DisposeResources method with the disposeManagedResources flag set to true, indicating
// that derived classes may release unmanaged resources and dispose of managed resources.
this.DisposeResources(true);
// Suppress finalization of this object (remove it from the finalization queue and
// prevent the destructor from being called).
GC.SuppressFinalize(this);
}
}
#endregion IDisposable Members
/// <summary>
/// Dispose resources. Override this method in derived classes. Unmanaged resources should always be released
/// when this method is called. Managed resources may only be disposed of if disposeManagedResources is true.
/// </summary>
/// <param name="disposeManagedResources">A value which indicates whether managed resources may be disposed of.</param>
protected abstract void DisposeResources(bool disposeManagedResources);
}
Best,
Comments
- Anonymous
October 05, 2011
"Totally Thread safe" is exaggerated. This code doesn't solve the problem of a thread Disposing the object while another thread is executing a method. "Quite Thread safe" probably :-)