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#
Created: 2/9/2005 8:00:27 AM

Current Projects

I create content for .NET Core. My work appears in the .NET Core documentation site. I'm primarily responsible for the section that will help you learn C#.

All of these projects are Open Source (using the Creative Commons license for content, and the MIT license for code). If you would like to contribute, visit our GitHub Repository. Or, if you have questions, comments, or ideas for improvement, please create an issue for us.

I'm also the president of Humanitarian Toolbox. We build Open Source software that supports Humanitarian Disaster Relief efforts. We'd appreciate any help you can give to our projects. Look at our GitHub home page to see a list of our current projects. See what interests you, and dive in.

Or, if you have a group of volunteers, talk to us about hosting a codeathon event.