106

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?

Jordan Parmer
  • 32,842
  • 27
  • 93
  • 118
  • 6
    Indeed, you should call Dispose on every Disposable object. You can do that easily using the `using` construct. – Luc Touraille Dec 04 '08 at 08:42
  • Ah, that makes sense. I had always wondered why the 'using' statement was used for file streams. I know it had something to do with the scope of the object, but I didn't put it in context with the IDisposable interface. – Jordan Parmer Dec 04 '08 at 14:09
  • 6
    One important point to remember is that a finalizer should *never* access any managed members of a class, as those members may no longer be valid references. – Dan Bryant Jun 09 '10 at 18:23

7 Answers7

134

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.

Community
  • 1
  • 1
Marc Gravell
  • 927,783
  • 236
  • 2,422
  • 2,784
  • Thanks! That makes perfect sense. I much appreciate the great response. – Jordan Parmer Dec 04 '08 at 14:08
  • 29
    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 Sep 09 '09 at 15:36
  • 1
    So Finalize is to release unmanaged resources. But Dispose could be used to release managed and unmanaged resources? – Dark_Knight Jul 02 '16 at 22:38
  • 2
    @Dark yes; because 6 levels down the manages chain could be an unmanaged one that needs prompt cleanup – Marc Gravell Jul 03 '16 at 00:43
  • 1
    @KevinJones Objects with a finalizer are guaranteed to survive gen 0, not 1, right? I read that in a book called .NET Performance. – David Klempfner Apr 23 '18 at 12:19
27

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.

Igal Tabachnik
  • 30,180
  • 15
  • 86
  • 150
9

There is a very good description on MSDN:

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
  • 92,232
  • 78
  • 284
  • 421
  • 1
    One major weakness of that description is that MS gives examples of unmanaged resources, but from what I've seen never actually defines the term. Since managed objects are generally only usable within managed code, one might think things used in unmanaged code are unmanaged resources, but that's not really true. A lot of unmanaged code doesn't use any resources, and some kinds of unmanaged resources such as events exist only in the managed-code universe. – supercat May 18 '15 at 16:19
  • 1
    If a short-lived object subscribes to an event from a long-lived object (e.g. it asks to be notified of any changes that occur within the short-lived object's lifetime), such an event should be considered an unmanaged resource, since failure to unsubscribe the event would cause the lifetime of the short-lived object to be extended to that of the long-lived object. If many thousands or millions of short-lived objects subscribed to an event but were abandoned without unsubscribing, that could cause a memory or CPU leak (since the time required to process each subscription would increase). – supercat May 18 '15 at 16:35
  • 1
    Another scenario involving unmanaged resources within managed code would be object allocation from pools. Especially if code needs to run in the .NET Micro Framework (whose garbage collector is much less efficient than the one on desktop machines) it may be helpful for code to have e.g. an array of structures, each of which may be marked "used" or "free". An allocation request should find a structure which is presently marked "free", mark it "used", and return an index to it; a release request should mark a structure as "free". If an allocation request returns e.g. 23, then... – supercat May 18 '15 at 16:39
  • 1
    ...if code never notifies the owner of the array that it no longer needs item #23, that array slot will never be usable by any other code. Such manual allocation out of array slots isn't used terribly often in desktop code since the GC is pretty efficient, but in code running on the Micro Framework it can make a huge difference. – supercat May 18 '15 at 16:41
9

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
  • 63,625
  • 65
  • 234
  • 426
  • 3
    This is the design pattern proposed by Microsoft in .NET documentation, but don't use it when your object is not IDisposable. http://msdn.microsoft.com/en-us/library/fs2xkftw%28v=vs.110%29.aspx – Zbyl Nov 23 '13 at 10:30
  • 1
    I can't think of any reason to offer a class with a finalizer that doesn't also have a Dispose method. – Jonathan Allen Nov 26 '13 at 22:38
5

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
  • 45,093
  • 12
  • 98
  • 145
3

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
  • 242
  • 2
  • 8
0

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
  • 4,103
  • 11
  • 33
  • 61