1 min read

IDisposable interface pattern

Example implementation of IDisposable

public class MyResource : IDisposable { public MyResource(IntPtr handle) { this.handle = handle; } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if(!this.disposed) { if(disposing) { component.Dispose(); } CloseHandle(handle); handle = IntPtr.Zero; disposed = true; } } ~MyResource() { Dispose(disposing: false); } }

MyResource object have pointer which is unmanaged. This is why this class should implement IDisposable interface. Implementation should be correct according to recommended pattern (see below for documentation).

There a re few points to highlight here:

  • IDisposable is meant to be used with using keyword.
  • using is calling IDisposable.Dispose method in the background
  • This method should be public then
  • protected Dispose(bool) method is meant to be called from finalizer via GC
  • SuppressFinalize disables this object from finalization mechanism in GC to prevent finalization code to be executed second time (see here)
  • Finalization is called from GC *only* if whoever is using this object will forget to use using or otherwise fail to call Dispose manually
  • Dispose must be save to call multiple times (if(!this.disposed))
  • Dispose(true) is meant to dispose also any other managed resources this implementation relies on
  • Dispose(false) is meant to be called from GC finalization mechanism. All managed resource are most likely already disposed so we cannot dispose them again

Further read:

https://learn.microsoft.com/en-us/dotnet/api/system.idisposable?view=net-6.0