SuppressFinalize
should only be called by a class that has a finalizer. It’s informing the Garbage Collector (GC) that this
object was cleaned up fully.
The recommended IDisposable
pattern when you have a finalizer is:
public class MyClass : IDisposable
{
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// called via myClass.Dispose().
// OK to use any private object references
}
// Release unmanaged resources.
// Set large fields to null.
disposed = true;
}
}
public void Dispose() // Implement IDisposable
{
Dispose(true);
GC.SuppressFinalize(this);
}
~MyClass() // the finalizer
{
Dispose(false);
}
}
Normally, the CLR keeps tabs on objects with a finalizer when they are created (making them more expensive to create). SuppressFinalize
tells the GC that the object was cleaned up properly and doesn’t need to go onto the finalizer queue. It looks like a C++ destructor, but doesn’t act anything like one.
The SuppressFinalize
optimization is not trivial, as your objects can live a long time waiting on the finalizer queue. Don’t be tempted to call SuppressFinalize
on other objects mind you. That’s a serious defect waiting to happen.
Design guidelines inform us that a finalizer isn’t necessary if your object implements IDisposable
, but if you have a finalizer you should implement IDisposable
to allow deterministic cleanup of your class.
Most of the time you should be able to get away with IDisposable
to clean up resources. You should only need a finalizer when your object holds onto unmanaged resources and you need to guarantee those resources are cleaned up.
Note: Sometimes coders will add a finalizer to debug builds of their own IDisposable
classes in order to test that code has disposed their IDisposable
object properly.
public void Dispose() // Implement IDisposable
{
Dispose(true);
#if DEBUG
GC.SuppressFinalize(this);
#endif
}
#if DEBUG
~MyClass() // the finalizer
{
Dispose(false);
}
#endif