AJ's blog

September 12, 2007

IDisposable reloaded

Filed under: .NET, .NET Framework, C#, Software Development — ajdotnet @ 6:01 pm

One of my last posts was about IDisposable. (Well regarded by the way, thanks for the feedback 🙂 ) I should have thougt that covered the topic, but actually there are a few things I missed. And some of them certainly should be mentioned in “The Last Article about IDisposable“.

Reference: [FDG] Framework Design Guidelines, Cwalina, Abrams 

To IDispose or not to IDispose?

A friend recently asked me “I hear you, but when should I actually implement IDisposable?”. Couriously my own answer didn’t convince me then. Now I’ll try better…

From the disposable pattern point of view there are only two relevant kinds of resources:

  1. unmanaged resources (i.e. not managed by the CLR)
  2. managed, disposable resources (i.e. classes implementing IDisposable)

Regarding unmanaged resources: When are you actually dealing with unmanaged resources? Well, talk about COM interop or P/Invoke and Win32 handles. In these cases I would have a look at the the SafeHandle class. This class does all and more of what any of us could think of. Once the resource is properly wrapped, I deal only with the wrapper which is a managed disposable ressource. Done.

That was easy, wasn’t it? Although unmanaged resources are the canonical justification for the IDisposable pattern (and finalizers for that matter), most developers rarely if ever deal with them directly. Database connection? DbConnection is a managed class. File handle? System.IO.File likewise.

Now for managed resources. When should you implement IDisposable? [FDG] gives two guidelines that in my opinion provide a nearly sufficient answer, thus I added a third one:

  • DO implement IDisposable on types containing instances of disposable types. In other words “aggregation” is the keyword.
  • CONSIDER implementing IDisposable if the type is likely to have subtypes that might contain disposable types.
  • My own addition to that: CONSIDER implementing IDisposable if you lay some kind of infrastructure … (see my last post for an example).

The first guideline is probably the most common case. And it has a pitfall. It says “instances of disposable types”, not “fields of disposable types”. There “Does any of the data members of my class have a type that implements IDisposable?” is actually the wrong question to ask! All the data member declaration tells you is the type of the data member; not the type of the instance it holds. Therefore the correct question would be “May any of the instances the data members of my class reference implement IDisposable?”. So take a hard look at your members of type object or any interface or base classes that would fall under the second guideline.

To finalize or not to finalize?

Most if not all articles about IDisposable present the pattern the way I did: Have the IDisposable.Dispose method call a virtual method Dispose(bool), have the finalizer call the same method. But [FDG] takes a different approach:

  1. The “Basic Dispose Pattern” only takes the IDisposable interface into account and effectively addresses managed resources. It does not include the finalizer!
  2. The “Finalizable Types” pattern acts as extension to the former, it adds the finalizer and deals with unmanaged resources.

The rationale for the basic dispose pattern? Well, why call the Dispose(bool) method from a finalizer if no unmanged ressource has to be freed? (And remember that you are not allowed to touch managed resources in the finalizer, as they might already be finalized.) Why pay for the finalizer and add the runtime effort (maintaining the object in the finalization queue) that comes with it in the first place?

At first I had some severe concerns (basically about the increased complexity and the implied risk of missing finalizers) and was inclined to contradict people like Herb Sutter 😳 . But actually it really simplifies the picture. The two kinds of resources mentioned above actually match the guidelines:

  • Unmanaged resources: SafeHandle implies (and goes beyond) “Finalizable Type“.
  • Managed ressouces: “Basic Dispose Pattern” and no finalizer!

The implication is interesting: No need for you to ever write a finalizer!

But Wait! What about these cases:

  • [FDG] also talks about “resources that need to be freed explicitely and that do not have finalizers”.
    In other words: unmanaged resources (already covered) or managed resources that are probably not implemented correctly (which rather needs a bugfix or workaround).
  • My initial concern: Having a class that implements IDisposable and at the same time omits the finalizer would be something unexpected and a surprise for most developers. So what if a derived class suddenly needed the finalizer and the developer wrongly assumed it was already there?
    The reason to need a finalizer would have to be an unmanaged resource. This calls for a wrapper class (e.g. SafeHandle) which in turn contradicts the use case.
  • What about classes that already implement a finalizer (and don’t have to)?
    Don’t worry. If it does the right thing it does nothing. So why bother?

Because it is rather unexpected, I’d like to emphasise the corollary: If you rely on SafeHandle or some similar wrapper class, you’ll never need to provide a finalizer! (This appears to contradict most IDisposable advice, including IDisposable Interface.)

Exceptions, exceptions, 5 cent each!

When .NET was still fresh there was a guideline not to throw exceptions in finalizers, because they would kill the finalizer thread and prevent other finalizers from being called. Early versions also didn’t guarantee that finalizers would be called during shutdown. Today the situation is as follows:

  • Objects will be finalized during shutdown by default (since .NET 1.0)
  • Exceptions will kill the process rather than the thread (since .NET 2.0). This really improves the situation, as the exception will not stay unnoticed (as before).
  • The guideline is that exceptions in finalizers should be limited to critical ones intendend to shut down the application. The guideline for Dispose is similar. ([FDG])
  • C# finalizers of derived classes will ensure that the finalizer of the base class is called even in the presence of an exception (see Finalize and Dispose Explained).

The last point is interesting. If you open the code of a class that overrides the finalizer in Reflector and choose C# format it will look like this:

~DerivedDisposableObject()
{
    this.Dispose(false);
}

The very same code in VB format however has a slightly different outfit:

Protected Overrides Sub Finalize() 
    Try 
        Me.Dispose(False) 
    Finally 
        MyBase.Finalize 
    End Try 
End Sub

All very well, the compiler does the work for us (as long as you are a decent C# developer 😀 ). But there still is one gap to fill: What about overriding the Dispose Method? Don’t the same issues apply here? They do. And does the compiler handle that as well? No, it doesn’t. Are we lost then? No, we aren’t.

First of all, I’m telling you how to do it right 😉 . Secondly, I convinced Microsoft to check whether you did follow my advice. There is a rule in FxCop and Code Analysis in Visual Studio respectively (CA2215:DisposeMethodsShouldCallBaseClassDispose). Take the following code snippet:

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        // free managed resources
    }
    
    // call base
    base.Dispose(disposing);
}

If you enable Code Analysis (I really wish this would be the default) it will generate the following warning:

MSBUILD : warning : CA2215 : Microsoft.Usage : Change DerivedObject.Dispose(Boolean):Void so that it calls its base class Dispose method for all code paths. Place the call in a finally block to ensure that resources are cleaned up when an exception is raised.

As it states, the correct version would be:

protected override void Dispose(bool disposing)
{
    try
    {
        if (disposing)
        {
            // free managed resources
        }
    }
    finally
    {
        // call base
        base.Dispose(disposing);
    }
}

Actually this little gem can be found in the documentation (e.g. in Implementing a Dispose Method), although rarely and never really advertised.

To null or not to null?

“Shouldn’t I set the data members to null?”. A question I got more than once in various incarnations.

So, just for the record: There is no need to set data members referencing disposable objects (or any object) to null. It does not help freeing resources and the garbage collector won’t work faster.
It might still be a good idea to set data members referencing disposable objects to null after disposing them. Just as a safety net. 

Other stuff…

Right about the same time I wrote my initial post, MS decided the topic is worth being adressed. There was an article on MSDN magazine in the CLR Inside Out column. I have to say, *ahaem*, it’s not nearly as complete as my coverage. But it mentions security and I got some hints on SafeHandle and try/finally in Dispose from it (the later one employed but not described, sic!).

Well, I hope THAT covers the topic. Or did I still miss something?

That’s all for now folks,
AJ.NET

kick it on DotNetKicks.com

Advertisement

6 Comments »

  1. That’s a very good hint to enable the fx cop condition: CA2215:DisposeMethodsShouldCallBaseClassDispose

    Will try that immediatley.

    Cheers
    Gerhard

    – Do we see us at the Basta in Mainz?

    Comment by Gerhard — September 14, 2007 @ 10:59 am

  2. @Gerhard: Thanks for the feedback.
    No, I won’t be at the basta (plenty of other SDX’lers, though). But I’ll probably be around in Frankfurt for quite some time, working for “the other project” 😉

    Comment by ajdotnet — September 14, 2007 @ 4:23 pm

  3. Regarding the “And remember that you are not allowed to touch managed resources in the finalizer”: You are not allowed to touch managed resources WHICH themselves declare a Finalizer. You are allowed to touch any managed resource which doesn’t declare a Finalizer.

    Anyone who ever read Joe Duffy’s 25 pages http://www.bluebytesoftware.com/blog/PermaLink.aspx?guid=88e62cdf-5919-4ac7-bc33-20c06ae539ae regarding this stuff, understands that it is hard to get Finalizers working correctly – threading et al.

    Comment by Cris — September 16, 2007 @ 6:34 pm

  4. I have implemented ‘Dispose(bool disposing)’in derived class as shown below, but it still gives me FxCop warning mentioned in your article. When I take the try – finally before “if (!disposed)” then it compiles properly. For other projects the pattern mentioned in MSDN works but only for this project it gives me warning.

    protected override void Dispose(bool disposing)
    {
    if (!disposed)
    {
    try
    {
    f (disposing)
    {

    }

    disposed = true;
    }
    finally
    {
    base.Dispose(disposing);
    }
    }

    }

    Comment by Mukund P. — April 28, 2008 @ 6:49 am

  5. Don’t use the try/finally in your Dispose(bool) method. You use it in the actual Dispose() method instead.

    private bool disposed;
    public sealed override void Dispose()
    {
    try
    {
    Dispose(true);
    GC.SuppressFinalize(this);
    }
    finally
    {
    base.Dispose();
    }
    }
    private void Dispose(bool disposing)
    {
    if (!this.disposed)
    {
    if (disposing)
    {
    // TODO: Dispose managed resources
    yourManagedObject.Dispose();
    }

    // TODO: clean up unmanaged resources
    CloseHandle(handle);
    handle = IntPtr.Zero;

    disposed = true;
    }
    }

    Problem I run into is what if there is an error during the cleanup of unmanaged resources? Your disposed flag is not set to true so you may end up in this method again trying to dispose any resources that have already been disposed or cleaned up before getting to the unmanaged resource that caused the original problem. Then you get into oddities.

    Comment by Dedric Mauriac — August 30, 2008 @ 1:52 am

  6. Great Article!

    Comment by Lars Corneliussen — January 13, 2009 @ 8:39 am


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: