47

If I write a class in C# that implements IDisposable, why isn't is sufficient for me to simply implement

public void Dispose(){ ... } 

to handle freeing any unmanaged resources?

Is

protected virtual void Dispose(bool disposing){ ... }

always necessary, sometimes necessary, or something else altogether?

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Mark Carpenter
  • 17,445
  • 22
  • 96
  • 149
  • In my class I've only unmanaged resources which needs cleaning and I'm implementing IDisposable with protected virtual void Dispose(bool disposing) as the static analysis forces it to do. In my case the "disposing" parameter has no use as I would like Finalizer and Dispose to do same thing. – AksharRoop Mar 11 '16 at 14:50

8 Answers8

48

The full pattern including a finalizer, introduction of a new virtual method and "sealing" of the original dispose method is very general purpose, covering all bases.

Unless you have direct handles on unmanaged resources (which should be almost never) you don't need a finalizer.

If you seal your class (and my views on sealing classes wherever possible are probably well known by now - design for inheritance or prohibit it) there's no point in introducing a virtual method.

I can't remember the last time I implemented IDisposable in a "complicated" way vs doing it in the most obvious way, e.g.

public void Dispose()
{
    somethingElse.Dispose();
}

One thing to note is that if you're going for really robust code, you should make sure that you don't try to do anything after you've been disposed, and throw ObjectDisposedException where appropriate. That's good advice for class libraries which will be used by developers all over the world, but it's a lot of work for very little gain if this is just going to be a class used within your own workspace.

Community
  • 1
  • 1
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
33

It's not strictly necessary. It is part of the recommended Disposable pattern. If you haven't read the Framework Design Guidelines section on this (9.3 in the first edition, don't have the second edition handy sorry) then you should. Try this link.

It's useful for distinguishing between disposable cleanup and finalizable garbage-collection-is-trashing-me.

You don't have to do it that way but you should read up on it and understand why this is recommended before discounting it as unnecessary.

Hamish Smith
  • 8,153
  • 1
  • 34
  • 48
16

There's a bit of bias in the MSFT docs about the disposable pattern. There are two reasons you should implement IDisposable:

  1. You've got fields of a type that implements IDisposable
  2. You've got a finalizer.

Case 1 is pretty common in most code. Case 2 is pretty common in code that Microsoft writes, they were the ones that wrote the managed wrappers around the unmanaged resources, the ones that need finalization. But should be very uncommon in your code. After all, you've got all those nice .NET classes to do the dirty work for you. You just have to call their Dispose() methods.

Only case 2 requires the disposable pattern. Microsoft needs to use it a lot. You'll just need the simple Dispose() most of the time.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • In my class I've only unmanaged resources which needs cleaning and I'm implementing IDisposable with protected virtual void Dispose(bool disposing) as the static analysis forces it to do. In my case the "disposing" parameter has no use as I would like Finalizer and Dispose to do same thing. – AksharRoop Mar 11 '16 at 14:49
  • Not sure what that comment is meant to convey. You are probably doing it wrong, use the SafeHandle and/or SafeBuffer wrapper classes. Critical finalizers are nice. Back to bullet 1. – Hans Passant Mar 11 '16 at 14:53
  • Ok, so my original question is what different Dispose(bool disposing) should do when value is true and value is false. What is disposing parameter used for? – AksharRoop Mar 11 '16 at 14:56
  • 3
    Click the Ask Question button to ask a question. – Hans Passant Mar 11 '16 at 15:04
  • @HansPassant What you meant was: Click the address bar at the top of your navigator and enter "www.google.com", then hit enter to ask a question. – Sebastien Feb 28 '17 at 20:54
5

In addition to the other great answers, you may want to check these articles:

Hosam Aly
  • 41,555
  • 36
  • 141
  • 182
  • 2
    The first article still includes the 'disposing' property in the simple dispose case, which is pointless. The really simple case is what Jon put in his example, with the possible addition of the 'virtual' keyword. – piers7 Feb 08 '10 at 01:05
4

The additional method with the bool disposing came out of a framework design guideline somewhere. It is simply a pattern to allow your class to have the dispose method be able to be called multiple times without throwing an exception. It isn't absolutely needed. Technically you could do it in the dispose method.

Bob
  • 97,670
  • 29
  • 122
  • 130
1

Just to expand on what others have said: it's not just that you don't need the 'complex dispose', it's that you actually don't want it, for performance reasons.

If you go the 'complex dispose' route, and implement a finalizer, and then forget to explicitly dispose your object, your object (and anything it references) will survive an extra GC generation before it's really disposed (since it has to hang around one more time for the CLR to call the finalizer). This just causes more memory pressure that you don't need. Additionally, calling the finalizer on a whole heap of objects has a non-trivial cost.

So avoid, unless you (or your derived types) have unmanaged resources.

Oh, and while we're in the area: methods on your class which handle events from others must be 'safe' in the face of being invoked after your class has been disposed. Simplest is to just perform a no-op if the class is disposed. See http://blogs.msdn.com/ericlippert/archive/2009/04/29/events-and-races.aspx

piers7
  • 4,174
  • 34
  • 47
1

One thing that it gives you is the ability to do work in Dispose() unrelated to finalization, and still clean up unmanaged resources.

Doing anything to a managed object other than 'yourself' in a finalizer is extremely... unpredictable. Most of this is due to the fact that your finalizers will be called in stage 2 shutdown of your AppDomain in a non-deterministic manner - so when your finalizer is called, it is extremely likely that objects that you still have references to have already been finalized.

Dispatching both the Dispose and finalizer calls to the same method allows you to share your shutdown code, while the boolean parameter allows you to skip the managed cleanup if you have any.

Also, the virtual-ness of the method provides an easy way for inheritors to add their own cleanup code, with less of a risk of inadvertently not calling yours.

kyoryu
  • 12,848
  • 2
  • 29
  • 33
1

If a class implements IDisposable.Dispose() and a derived class needs to add additional logic, that class must expose some kind of Dispose method that the derived class can chain to. Since some classes may implement IDisposable.Dispose() without having a public Dispose() method, it's useful to have a virtual method which will be protected in all implementations of IDisposable regardless of whether they have a public Dispose method or not. In most cases, the bool argument isn't really meaningful but should be thought of as a dummy argument to make the protected virtual Dispose(bool) have a different signature from the may-be-or-maybe-not-public Dispose().

Classes which doesn't use a protected virtual Dispose(bool) will require derived classes to handle their cleanup logic in a fashion which differs from the convention. Some languages like C++/CLI which are only equipped to extend IDisposable implementations which follow that convention may be unable to derive classes from non-standard implementations.

supercat
  • 77,689
  • 9
  • 166
  • 211