Bill Blogs in C#

Bill Wagner discusses C#, LINQ, and other items of interest

GC.SuppressFinalize in constructors?
SQLConnection, for one, calls GC.SuppressFinalization() in its constructor. Why would you do that?

A fried of mine asked about the practice of calling GC.SuppressFinalize() in a constructor. He noticed it in the SQLConnection constructor. It’s also present in a number of other components, such as the Windows Forms Datagrid. Is it safe? Why do it?

Calling GC.SuppressFinalize() is a performance optimization that a number of classes that derive from System.ComponentModel.Component use. Personally, I think it can be unsafe, so adopt it with caution.

System.ComponentModel.Component implements IDisposable and provides a finalizer so that all derived classes can cleanup both managed and unmanaged resources.

The pertinent pieces of code are here:

// IDisposable.Dispose:
// delegates the work to Dispose( bool )
// Then, notify the GC that Finalization is no longer needed.
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}

// Finalizer.
// Delegates the work to Dispose( bool )
~Component()
{
this.Dispose(false);
}





// hook for all derived classes:
protected virtual void Dispose(bool disposing) {
// KEY POINT: If called from the finalizer,
// there's nothing to do.
if (!disposing)
{
return;
}
// much other work elided
}

SQLConnection overrides Dispose( bool ) to close the connection when IDisposable.Dispose() is called:

protected override void Dispose(bool disposing) {
if (disposing)
{
switch (this._objectState)
{
case ConnectionState.Open:
{
this.Close();
break;
}
}
this._constr = null;
}
// KEY POINT: Note that there is no 'else' clause.
// No work gets done when called by the finalizer.
base.Dispose(disposing);
}

Just like in Component, nothing actually happens when this is called from the Finalizer. That means the finalizer for SQLConnection doesn't really need to be called under any circumstances, even when the user forgets to call IDisposable.Dispose()

Well, Finalizers extract a rather heavy performance penalty on the garbage collector. And, sometimes people forget using clauses, or calling Dispose() diligently. So, the constructor for SQLConnection calls GC.SuppressFinalization( this ) so that the GC ignores the presence of the finalizer, and you don't need to pay the performance penalty if you forget to call IDisposable.Dispose().

This technique is correct only because:

  1. SQLConnection is sealed, so no one can create a class derived from SQLConnection that actually does work when the finalizer executes.
  2. SQLConnection, and all base classes: System.ComponentModel.Component, System.MarshalByRefObject, and System.Object do not perform any cleanup in their finalizers.

The reason I find this a bit unsafe is that it's entirely possible for someone to add code breaking (2) above in some future release. I don't advocate it for general use. But, SQLConnection gets used a lot, and here, the performance costs probably add up. And, hopefully, if one of the base classes does make that change, everyone gets notified.

I'll close with my own question: Why doesn't SQLConnection need to do any work in its finalizer? Once again, if you use Reflector, you'll see quite a bit of code in the Close() method. What happens if that never gets called? If you know, please contact me.



Implement the Standard Dispose Idiom
I covered this in depth in Effective C#
Published Wed, Feb 9 2005 6:00 AM by wwagner
Filed under: ,