views:

219

answers:

3

Is there a catch or hidden problem in using a DisposableBase base class instead of recoding the Dispose pattern on every class?

Why aren't everyone using such a relevant class?

Edits:

  1. I naturally only meant classes that implement IDisposable

  2. I know it uses up the option for inheritance, but I'm willing to pay the price (at least when I can and it doesn't hurt me otherwise).

  3. When I can seal the class, I do - but I have some cases where I want the base of an inheritance hierarchy to be Disposable.

+2  A: 

You don't need to implement Dispose() on every class - just those with something that needs deterministic cleanup. Re a Disposable base-class, I'm not entirely sure it provides a whole lot - IDisposable isn't a complex interface. The main time it might be useful is if you are handling unmanaged resources and want a finalizer, but even then it isn't much code.

Personally, I wouldn't bother with such a base class. In particular, inheritance (in a single-inheritance world) gets restrictive very quickly. But more to the point, overriding a method isn't much different to simply providing a public Dispose() method.

Again: you only need a finalizer etc if you are handling unmanaged objects.

If I had a lot of these (unmanaged resouces), I might see whether I could get PostSharp to do the work for me. I don't know if one already exists, but it might be possible to create an aspect that handles (in particular) the finalizer etc. Who knows...

Marc Gravell
See Edit in the original post.
ripper234
+2  A: 

Well, it uses up your one option for inheritance to describe a single aspect of your class - that's not ideal, IMO. It would be interesting to try to do something with composition, where you have a reference to a DisposableHelper and the implementation of IDisposable just calls helper.Dispose, which has the rest of the boilerplate logic in - and can call back to your code via a callback delegate. Hmm. Subclasses could subscribe to a protected Disposing event to register "I need to do something"... it might be worth looking at some time.

Personally I don't find myself implementing IDisposable often enough to make it an issue - and when I do, I typically seal my classes anyway, so half of the stuff in the pattern becomes a non-issue.

Jon Skeet
I don't think composition works. The helper class might have been garbage collected before the IDisposable class.
Mendelt
The reference to the helper would prevent the GC from doing so
Greg Dean
The GC only uses references that originate from an object that's actually in scope somewhere. The helper needs to be references from something other than your object to be guaranteed to be there when you need it. Keeping a helper collection somewhere central might help but this seems tricky.
Mendelt
Mendelt: The helper and the "real" class would be finalized before either instance could be garbage collected.
Jon Skeet
+1  A: 

As Marc Gravell said, you only need a finalizer if you are handling unmanaged objects. Introducing an unnecessary finalizer in a base class is a bad idea, as per the reasons in section 1.1.4 of the Dispose, Finalization, and Resource Management guidelines:

There is a real cost associated with instances with finalizers, both from a performance and code complexity standpoint. ... Finalization increases the cost and duration of your object’s lifetime as each finalizable object must be placed on a special finalizer registration queue when allocated, essentially creating an extra pointer-sized field to refer to your object. Moreover, objects in this queue get walked during GC, processed, and eventually promoted to yet another queue that the GC uses to execute finalizers. Increasing the number of finalizable objects directly correlates to more objects being promoted to higher generations, and an increased amount of time spent by the GC walking queues, moving pointers around, and executing finalizers. Also, by keeping your object’s state around longer, you tend to use memory for a longer period of time, which leads to an increase in working set.

If you use SafeHandle (and related classes), it's unlikely that any classes that derive from DisposableBase would ever need to be finalized.

Bradley Grainger