I have covered the IDisposable interface in my previous posts IDisposable and using in C# and Implementing IDisposable. To make the implementation of IDisposable easier, I have written an abstract base class that handles the details of the IDisposable pattern. The objectives of the class is to:
Provide a simple, reusable implementation of the disposable pattern.
Pass all code analysis rules.
The Disposable Class
/// <summary>/// A general implementation of the disposable pattern. /// See http://coding.abel.nu/2012/01/disposable/// </summary>publicabstractclass Disposable : IDisposable
{/// <summary>/// Implementation of IDisposable.Dispose method./// </summary>publicvoid Dispose(){
Dispose(true);
GC.SuppressFinalize(this);}/// <summary>/// Is this instance disposed?/// </summary>protectedbool Disposed {get;privateset;}/// <summary>/// Dispose worker method. See http://coding.abel.nu/2012/01/disposable/// </summary>/// <param name="disposing">Are we disposing? /// Otherwise we're finalizing.</param>protectedvirtualvoid Dispose(bool disposing){
Disposed =true;}/// <summary>/// Finalizer./// </summary>
~Disposable(){
Dispose(false);}}
/// <summary>
/// A general implementation of the disposable pattern.
/// See http://coding.abel.nu/2012/01/disposable
/// </summary>
public abstract class Disposable : IDisposable
{
/// <summary>
/// Implementation of IDisposable.Dispose method.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Is this instance disposed?
/// </summary>
protected bool Disposed { get; private set; }
/// <summary>
/// Dispose worker method. See http://coding.abel.nu/2012/01/disposable
/// </summary>
/// <param name="disposing">Are we disposing?
/// Otherwise we're finalizing.</param>
protected virtual void Dispose(bool disposing)
{
Disposed = true;
}
/// <summary>
/// Finalizer.
/// </summary>
~Disposable()
{
Dispose(false);
}
}
Rewriting the LogWriter
In the Implementing IDisposable post I used a LogWriter class as a sample. With the Disposable base class it can be rewritten.
public class LogWriterFromDisposable : Disposable
{
private StreamWriter m_Stream;
public LogWriterFromDisposable(string logFile)
{
m_Stream = new StreamWriter(logFile, true);
m_Stream.WriteLine("Starting logging at {0}", DateTime.Now);
}
public void WriteLine(string message)
{
m_Stream.WriteLine(message);
}
protected override void Dispose(bool disposing)
{
if (!Disposed && disposing)
{
m_Stream.Dispose();
}
base.Dispose(disposing);
}
}
Instead of having an entire section for IDisposable there is now just one method.
Limitations of a Base Class
As C# only supports single inheritance it is only possible to use the Disposable base class if there is no need to inherit another class, but that is not as hard a limitation at all. Any subclass should always be possible to use anywhere a base class is expected. If the subclass introduced a requirement of disposing, that principle would not hold. It is always preferable to have the base class in a class hierarchy implement IDisposable if any class requires it. Or put the other way: Never implement IDisposable in a sub class if the base class doesn’t.
Yes, it’s somewhat cleaner. But it also requires the sub class to implement the Dispose(bool) method. And there are cases where that’s not needed. Consider if you have a class that implements an interface that inherits from IDisposable. But your specific class does not have any resources that need to be disposed. Then you could just derive form the Disposable base class to meet the IDisposable requirement in a way that allows anyone subclassing your class to handle unmanaged resources.
You're currently writing a reply to an existing comment, so the comment form is busy elsewhere. To make a new
comment (that isn't a reply to an existing ocmment), you have to cancel that reply.
Samuel on 2015-12-09
You may also add the support for multi dispose calls by adding a disposed variable checked in Dispose() call.
Adam Hancock on 2017-02-17
This is cleaner code, no?
Anders Abel on 2017-02-21
Yes, it’s somewhat cleaner. But it also requires the sub class to implement the
Dispose(bool)
method. And there are cases where that’s not needed. Consider if you have a class that implements an interface that inherits fromIDisposable
. But your specific class does not have any resources that need to be disposed. Then you could just derive form theDisposable
base class to meet theIDisposable
requirement in a way that allows anyone subclassing your class to handle unmanaged resources.