views:

3673

answers:

9

When would I implement IDispose on a class as opposed to a destructor? I read this article, but I'm still missing the point.

My assumption is that if I implement IDispose on an object, I can explicitly 'destruct' it as opposed to waiting for the garbage collector to do it. Is this correct?

Does that mean I should always explicitly call Dispose on an object? What are some common examples of this?

+24  A: 

A finalizer (aka destructor) is part of garbage collection (GC) - it is indeterminate when (or even if) this happens, as GC mainly happens as a result of memory pressure (i.e. need more space). Finalizers are usually only used for cleaning up unmanaged resources, since managed resources will have their own collection/disposal.

Hence IDisposable is used to deterministically clean up objects, i.e. now. It doesn't collect the object's memory (that still belongs to GC) - but is used for example to close files, database connections, etc.

There are lots of previous topics on this:

Finally, note that it is not uncommon for an IDisposable object to also have a finalizer; in this case, Dispose() usually calls GC.SuppressFinalize(this), meaning that GC doesn't run the finalizer - it simply throws the memory away (much cheaper). The finalizer still runs if you forget to Dispose() the object.

Marc Gravell
Thanks! That makes perfect sense. I much appreciate the great response.
j0rd4n
One extra thing to say. Do not add a finalizer to your class unless you really, really need one. If you add a finalizer (destructor) the GC has to call it (even an empty finalizer) and to call it the object will always survive a gen 1 garbage collect. This will impede and slow down the GC. That's wht Marc says to call SuppressFinalize in the above code
Kevin Jones
+6  A: 

The role of the Finalize() method is to ensure that a .NET object can clean up unmanaged resources when garbage collected. However, objects such as database connections or file handlers should be released as soon as possible, instead on relying on garbage collection. For that you should implement IDisposable interface, and release your resources in the Dispose() method.

hmemcpy
+3  A: 

There is a very good description on MSDN http://msdn.microsoft.com/en-us/library/system.idisposable.aspx

The primary use of this interface is to release unmanaged resources. The garbage collector automatically releases the memory allocated to a managed object when that object is no longer used. However, it is not possible to predict when garbage collection will occur. Furthermore, the garbage collector has no knowledge of unmanaged resources such as window handles, or open files and streams.

Use the Dispose method of this interface to explicitly release unmanaged resources in conjunction with the garbage collector. The consumer of an object can call this method when the object is no longer needed.

abatishchev
A: 

It's pretty simple really. I know it's been answered but I'll try again but will try to keep it as simple as possible.

A destructor should generally never be used. It is only run .net wants it to run. It will only run after a garbage collectoin cycle. It may never actually be run during the lifecycle of your application. For this reason, you should not ever put any code in a destructor that 'must' be run. You also can't rely on any existing objects within the class to exist when it runs (they may have already been cleaned up as the order in which destructors run in is not garanteed).

IDisposible should be used whenever you have an object that creates resources that need cleaning up (ie, file and graphics handles). In fact, many argue that anything you put in a destructor should be putin IDisposable due to the reasons listed above.

Most classes will call dispose when the finalizer is executed but this is simply there as a safe guard and should never be relied upon. You should explicitly dispose anything that implements IDisposable when you're done with it. If you do implement IDisposable, you should call dispose in finalizer. See http://msdn.microsoft.com/en-us/library/system.idisposable.aspx for an example.

DaEagle
No, the garbage collector never calls Dispose(). It *only* calls the finalizer.
Marc Gravell
Fixed that. Classes are supposed to call dispose in their finalizer, but they don't have to.
DaEagle
+4  A: 

The only thing that should be in a C# destructor is this line:

Dispose(False);

That's it. Nothing else should ever be in that method.

Jonathan Allen
A: 

Here is another fine article which clears up some of the mist surrounding IDisposable, the GC and dispose.

Chris Lyons WebLog Demystifying Dispose

scope_creep
+2  A: 

Your question regarding whether or not you should always call Dispose is usually a heated debate. See this blog for an interesting perspective from respected individuals in the .NET community.

Personally, I think Jeffrey Richter's position that calling Dispose is not mandatory is incredibly weak. He gives two examples to justify his opinion.

In the first example he says calling Dispose on Windows Forms controls is tedious and unnecessary in mainstream scenarios. However, he fails to mention that Dispose actually is called automatically by control containers in those mainstream scenarios.

In the second example he states that a developer may incorrectly assume that the instance from IAsyncResult.WaitHandle should be aggressively disposed without realizing that the property lazily initializes the wait handle resulting in an unnecessary performance penalty. But, the problem with this example is that the IAsyncResult itself does not adhere to Microsoft's own published guidelines for dealing with IDisposable objects. That is if a class holds a reference to an IDisposable type then the class itself should implement IDisposable. If IAsyncResult followed that rule then its own Dispose method could make the decision regarding which of its constituent members needs disposing.

So unless someone has a more compelling argument I am going to stay in the "always call Dispose" camp with the understanding that there are going to be some fringe cases that arise mostly out of poor design choices.

Brian Gideon
A: 

This may not be directly related to the question, but if you're interested, I came up with a trick to MAKE SURE that if your class implements IDisposable, the user of any instance of that class calls your Dispose(): http://dalebarnardonwpf.wordpress.com/2009/09/12/an-idisposable-enforcement-trick/

Dale Barnard
A: 

I sometimes recommend implementing the IDisposable pattern even if your class has no unmanaged resources to worry about. I wrote a blog entry on the subject if you're interested: http://dalebarnardonwpf.wordpress.com/2009/09/12/implement-idisposable-more/

Dale Barnard
John Saunders
I tried to include both links in one, but since I'm a new user, it only allowed one link per post.
Dale Barnard