February 19, 2008

Disposed objects

There are a few rules about disposed objects. First, calling Dispose on an already disposed object should do nothing. Second, calling any other property or method on an already disposed object should throw an ObjectDisposedException.

Either way, you'll need a way to determine whether an instance of your disposable class has been disposed. The easiest and most obvious way is to have a simple Boolean member that is set to true when the object is disposed.

More often than not, we find that setting a field to null that wouldn't otherwise be null works just as well. Commonly, that field needs to be disposed, so we use a utility method that can be used to dispose a field and set it to null – unless it is already null. Using this method ensures that calling Dispose a second time won't throw a NullReferenceException.

publicstaticclassDisposableUtility

{

publicstaticvoid Dispose<T>(ref T obj) where T : class, IDisposable

{

if (obj != null)

{

obj.Dispose();

obj = null;

}

}

}

An easy way to throw ObjectDisposedException when your object has already been disposed is to define a private (or protected) method that throws the exception if necessary; just call that method at the beginning of every property or method definition of your class (besides Dispose, of course).

sealedclassFileReader : IDisposable

{

public FileReader(string strFilePath)

{

m_stream = newFileStream(strFilePath, FileMode.Open);

}

publicobject ReadNext()

{

VerifyNotDisposed();

object obj = null;

// ...

return obj;

}

publicvoid Dispose()

{

DisposableUtility.Dispose(ref m_stream);

}

privatevoid VerifyNotDisposed()

{

if (m_stream == null)

thrownewObjectDisposedException(GetType().Name);

}

Stream m_stream;

}

Nothing too complicated, but it's easy to forget the two rules of disposed objects. Get in the habit of verifying both rules when you write your unit tests.