Archive

Posts Tagged ‘Dispose’

CA1816 – Dispose Pattern

April 13, 2008 Leave a comment

If you have code analysis enabled in your project you might get the following code analysis message on a bunch of your classes even when you have not implemented any finalizers.

Warning 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.

The explanations for this rule at MSDN Dispose methods should call SuppressFinalize for .NET Framework 2.0 says:

"The Dispose method lets users release resources at any time prior to the object becoming available for garbage collection. If the Dispose method is called, it frees the resources of the object, making finalization unnecessary. Dispose should call SuppressFinalize so the garbage collector does not call the finalizer of the object."

The .NET Framework 3.5 version Call GC.SuppressFinalize correctly is a bit different and says:

"The IDisposable.Dispose method lets users release resources at any time before the object becoming available for garbage collection. If the IDisposable.Dispose method is called, it frees resources of the object. This makes finalization unnecessary. IDisposable.Dispose should call GC.SuppressFinalize so the garbage collector does not call the finalizer of the object. 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."

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

Looking 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.

A simpler explanation of the above rules would be "A disposable type needs to implement IDisposable and 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 ."

//example dispose pattern using System; using System.Data.SqlClient; namespace Samples { public class DatabaseConnector : IDisposable { private SqlConnection _Connection = new SqlConnection(); public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing) { if (_Connection != null) { _Connection.Dispose(); _Connection = null; } } } } }

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 seems to be a good idea to go ahead and use it and that’s what the warning is telling.

 

Tags: ,