March 27, 2006

Dispose Pattern

Explains how to implement IEnumerator and Contains basic IDispose pattern and more Msdn Guidelines on Implementing IDisposable and Equals Operators


Design pattern for a base class with unmanaged resources.

// Design pattern for a base class with unmanaged resources.
public class Base: IDisposable
{

#region Dispose Implementation

// Use C# 'destructor' style syntax for a finalizer.
// Finalizer is only required when the class has Unmanaged resources
// but can also be used to detect memory leaks
~Base() 
{
  // This is defensive code to ensure that even if you forget to call Dispose() unmanaged objects stil get freed
  Dispose (false); // Dispose of unmanaged resources 
  Debug.Assert(false, nameof(Base) + " with id of " + someId + " was not disposed of"); // Useful for detecting memory leaks
}

protected bool _isDisposed;

//Implement IDisposable.
public void Dispose() 
{
  Dispose(true); // Dispose of managed and unmanaged resources
  GC.SuppressFinalize(this); // Not required now
}

protected virtual void Dispose(bool disposing) 
{
  if (_isDisposed)
    return;
    
  if (disposing) 
  {
     // Free other state (managed objects).
  }
      
  // Free your own state (unmanaged objects).
  // Set large fields to null.
  _isDisposed = true;
}

#endregion Dispose Implementation

...
}

Design pattern for a derived class

   
// Design pattern for a derived class.
public class Derived : Base
{  

#region Dispose Implementation 

   protected override void Dispose(bool disposing) 
   {
      if (_isDisposed)
        return;
    
      if (disposing) 
      {
         // Free other state (managed objects).
      }
      
      // Release unmanaged resources here
      // Set large fields to null.
      
      // Call Dispose on your base class.
      base.Dispose(disposing);
   }
   
   // The derived class does not have a Finalize method
   // or a Dispose method with parameters because it inherits
   // them from the base class.

#endregion Dispose Implementation

}

Finally the simplest case

// Design pattern for a simple class with only small unmanaged resources.
public class SimplestDispose : IDisposable
{

#region Dispose Implementation

#region DEBUG
// Finalizer is only used to detect memory leaks
~SimplestDispose() 
{
  Debug.Assert(false, nameof(Base) + " with id of " + someId + " was not disposed of"); // Useful for detecting memory leaks
}
#endregion DEBUG

//Implement IDisposable.
public void Dispose() 
{
  // Dispose of managed resources here
  
#if DEBUG  
  GC.SuppressFinalize(this); // Not required now except for detecting memory leaks
#endif
}

#endregion Dispose Implementation

...
}

No comments: