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