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