Wednesday, March 22, 2006 - 14:08

Finalize, Dispose, and London

I haven't blogged for a while, because I was busy packing up all my stuff and moving to London. But now I've been here for just over a week, have a room in a flat, and am in the middle of job interviews, and recovering from the apparently traditional adjusting-to-London's-climate cold, and I figured that it's about time to say something.

London's cool - more familiar than the States, but different enough not to be boring. I'm starting to find my way around, and at some point in the next week I'll write up my "South African's Guide to London", which just might, possibly, be mildly interesting or vaguely useful to any other South Africans coming over here, specifically ones who don't have a friend here to help them out (luckily, I did :-).

But the next couple of blog entries are going to be dev related - I haven't been coding for over a month, and my skillz are getting a bit rusty, so I've been revising stuff for the tech interviews that I've been going through. And while the MSDN is really useful, I thought it might be useful (to me, at least) to have some of the tricky stuff up here, so that it's easy (for me, at least) to find.
So without further ado, on to Dispose and Finalize.

This is a tricky subject, and I don't really know enough to debate all the ins and outs. Some people say, never implement Finalize, but from what I see in the MSDN you kinda have to - if you have unmanaged resources that you need to clean up, of course, like a database connection. Otherwise you probably shouldn't, since it is pretty slow.

The best way to go about it is to implement IDisposable. This has the advantage that anyone using your class/resource can use the 'using' clause to make sure that Dispose() is automatically called when it goes out of scope, even if an exception is thrown (sure, they could use a try-catch-finally block, but they might not).
So the MSDN-approved pattern is this (at least, in my version of the MSDN):

1. Implement a Dispose() method. This will be called if the instantiater of the class uses the using clause, or whenever they call Dispose() explicity. The Dispose() method should look something like this:
public void Dispose()
{
  Dispose(true);
  GC.SuppressFinalize(this);
}

You want to suppress the garbage collector, since you've already cleaned up everything in the class (and of course, for all the objects it contains - don't forget that bit!).

2. Implement the Dispose(bool) method:
public void Dispose(bool Disposing)
{
  if (Disposing)
  {
     // dispose the managed resources
     // e.g. if you had a Component object, call      //Component.Dispose()
}

 // regardless, clean up your unmanaged resources,
 // like handles or DB connections
}


3. Implement Finalize()
~MyClass()
{
 Dispose(false);
}

That way you cover all your bases - if the user of your class calls Dispose, it'll dispose of everything, otherwise the garbage collector will call Finalize and your unmanaged resources will be cleaned up.

You need to remember that there's no guarantee of the order in which objects will be disposed or finalized, so you shouldn't reference any external objects. And your code shouldn't throw any exceptions, even if Dispose() is called more than once - a good thing to do is have a field called something like 'isDisposed', and then check that in the beginning of your Dispose() method and do nothing if it's true. Equally, you should check the value of isDisposed in every class method, and throw an ObjectDisposedException if it has been disposed already. Also, derived classes should implement their own Dispose(bool) methods, which call that of their base class.

And that's that for Finalize and Dispose. Next time - maybe design patterns, and where to find them? Maybe. Also coming up: Structs vs Classes, Custom Attributes, using SQL in C#, and the other perennial interview favourite, Delegates (both on their own, and together with Events).

Labels:

0 Comments:

Post a Comment

<< Home