Code Analysis - CA1816 (CallGCSuppressFinalize)


N

NvrBst

Code Analysis always returns the following message on a bunch of my
classes.

Warning 75 CA1816 : Microsoft.Usage : Change 'xxx.Dispose()' to call
'GC.SuppressFinalize(object)'. This will prevent unnecessary
finalization of the object once it has been disposed and it has fallen
out of scope.


None of my classes have a finalizer, they all simply have the
following (or very simular to the following)
----------
private bool disposed = false;
public void Dispose() { Dispose(true); }
protected virtual void Dispose(bool disposing) {
if(!disposed) {
if(disposing && slimLock != null) slimLock.Dispose();
disposed = true;
}
}
----------

Joe Duffy's Weblog (http://www.bluebytesoftware.com/blog/2005/04/08/
DGUpdateDisposeFinalizationAndResourceManagement.aspx)
--Says not to call Dispose if my class doesn't have the "~MyClass()"
finalizer method.

MSDN (http://msdn2.microsoft.com/en-us/library/ms182269.aspx)
--Says, basically, don't ignore this warning and to add the code.


Should I be calling the SupressFinalize anyway (IE doesn't hurt
anything performance wise), or just ignore the Code Analysis warning?
Or 'something strange with my code because I dont get the warning'
kind of thing?

Thanks :) NB
 
Ad

Advertisements

M

Misbah Arefin

A disposable type needs to implement IDisposable & provide a public
Dispose(void) method that ends the object’s lifetime. If the type is not
sealed, it should provide a protected Dispose(bool disposing) method where
the actual cleanup logic lives. Dispose(void) then calls Dispose(true)
followed by GC.SuppressFinalize(this). If your object needs a finalizer,
then the finalizer calls Dispose(false). The cleanup logic in Dispose(bool)
needs to be written to run correctly when called explicitly from
Dispose(void), as well as from a finalizer thread. Dispose(void) and
Dispose(bool) should be safely runnable multiple times, with no ill effects

//the dispose pattern
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
if (disposing)
{
//release objects
if (_Connection != null)
{
_Connection.Dispose();
_Connection = null;
}
}
}
 
N

NvrBst

Peter && Misbah

I just found it very strange that they'd have us call a
SuppressFinalize when the class has no filalizer (IE, no "~MyClass()
{}"). The class has no unmanaged clean-up, so I'm 99% sure my class
doesn't want to create an empty "~MyClass() {}", else it might get the
performance hit when its not needed.

Also when choosing the .NET2.0 version of CA1816 it says "Cause: A
type implements System.IDisposable.Dispose, has a finalizer, and
Dispose does not call System.GC.SuppressFinalize(System.Object)."
http://msdn2.microsoft.com/en-us/library/ms182269(VS.80).aspx

But when choosing the .NET3.5 version of CA1816, all reference about
the "has a finalizer" are removed under cause.
http://msdn2.microsoft.com/en-us/library/ms182269.aspx


Does it mean that in .NET3.5 they added some kind of code optimization
that realizes I didn't overload the finalizer object and thus the
"SupressFinalizer" line basically does nothing, so just add it anyway
to be safe for the future is what code analysis is telling me?

--Joe Duffy's Weblog Also States--
Simple Example w/out Finalize (C#): For the majority of types
implementing the Dispose pattern, you will not need to implement your
own Finalize method. This example shows the simple case, for example
when using a SafeHandle to take care of the implicit cleanup:


And then shows an example where it does not call SupressFinalize, but
this is a couple years old so might be .NET 2.0 specific (not related
to .NET 3.5).


I realize having the Supress there probably doesn't affect much (even
in .NET 2.0) if you don't have a finalizer, but I'm always curious
about little things like this.

NB
 
Ad

Advertisements

N

NvrBst

[...]
Also when choosing the .NET2.0 version of CA1816 it says "Cause: A
type implements System.IDisposable.Dispose, has a finalizer, and
Dispose does not call System.GC.SuppressFinalize(System.Object)."
http://msdn2.microsoft.com/en-us/library/ms182269(VS.80).aspx
But when choosing the .NET3.5 version of CA1816, all reference about
the "has a finalizer" are removed under cause.
http://msdn2.microsoft.com/en-us/library/ms182269.aspx

Look more carefully at the explanation of the latter.  In particular, this  
part:

     To prevent derived types with finalizers from having to
     re-implement [System][.][IDisposable] and to call it,
     unsealed types without finalizers should still call
     GC.SuppressFinalize.

In other words, they are saying that if your class isn't sealed, then even 
if you don't implement your own finalizer, you should still call  
SuppressFinalize() in your Dispose() method.  That way, derived types only  
have to implement the protected Dispose(bool) method, and can rely on your 
base class implementation to deal with finalizer issues.
Does it mean that in .NET3.5 they added some kind of code optimization
that realizes I didn't overload the finalizer object and thus the
"SupressFinalizer" line basically does nothing, so just add it anyway
to be safe for the future is what code analysis is telling me?

The call to SuppressFinalize() is very inexpensive in any case.  If you  
don't have a finalizer, then I'd agree that strictly speaking it's not  
necessary.  However, it does seem to me that it's good form to go ahead  
and use it.  And that's what the warning is telling you.

Pete

Ahh, thats exactly what I was looking for thanks :) I remember
reading the .NET 2.0 version, and then skimming the .NET 3.5 version
after realizing I was on .NET 2.0. I should of been more attentitive
to the newer one :)

I understand now why it should have SuppressFinalize :) Thanks
Kindly.

NB
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top