Skip to content

Implement IDisposable

jbe2277 edited this page Sep 24, 2023 · 13 revisions

The primary use of the IDisposable interface is to release unmanaged resources. But it can also be useful for some managed-only cleanup (e.g. removing of event handlers). The usage of this interface is quite attractive because of the using C# keyword.

The Dispose Pattern provides a good introduction on how to implement the interface and how to use it. This article provides some extended guidelines and some minor adaptions of the MSDN description.

  • Avoid to implement the finalizer (C# destructor) because of performance reasons.
    • The finalizer is only needed if the class is directly responsible for releasing unmanaged resources.
    • Prefer the SafeHandle class for handling unmanaged resources.
  • Do Not throw exceptions in the dispose implementation.
    • A finalizer (C# destructor) might call Dispose. The finalizer is called by the Garbage Collector. An exception must not be thrown here.
    • The using C# keyword hides the Dispose call and therefore an exception is not expected here.
    • Furthermore, Dispose might be called from infrastructure code like IoC Containers which do not know how to handle exceptions which are thrown during disposing objects.
  • Consider that the Dispose method might be called more than once.
    • Ignore subsequent Dispose calls instead of throwing the ObjectDisposedException.
  • Consider thread-safety because finalizers are called by a separate Thread.
  • Keep care when the method gets called by the finalizer (disposing is false).
    • In this case do not access other objects. These objects might already be finalized because the garbage collector disposes them in an unpredictable order.
public class SampleClass : IDisposable
{
    // Consider thread-safety because finalizers are called by a separate Thread.
    private int isDisposed;

    public void Dispose()
    {
        GC.SuppressFinalize(this);
        Dispose(true);
    }

    protected bool IsDisposed => isDisposed != 0;

    // Call this method from a subclass when you implement a finalizer (destructor).
    protected void Dispose(bool disposing)
    {
        if (Interlocked.CompareExchange(ref isDisposed, 1, 0) != 0) return;

        OnDispose(disposing);
        if (disposing)
        {
            // Cleanup and call Dispose on objects for which this class is responsible 
            // here ...
        }
        // Free unmanaged resources here ...
    }

    // Override this method in a subclass to free, release or reset any resources.
    protected virtual void OnDispose(bool disposing) { }
}

Further readings

  1. Dispose Pattern
  2. IDisposable Interface
  3. CA1063: Implement IDisposable correctly