4

I was implementing Finalize and Dispose in my classes, I implemented IDisposable on my parent class and override the Dispose(bool) overload in my child classes. I was not sure

  1. whether to use a duplicate isDisposed variable(as its already there in base class) or not?
  2. Whether to implement a finalizer in child class too or not?

Both these things are done in example given here -

http://guides.brucejmack.biz/CodeRules/FxCop/Docs/Rules/Usage/DisposeMethodsShouldCallBaseClassDispose.html

Whereas example in this MSDN article doesn't have any of these two - http://msdn.microsoft.com/en-us/library/b1yfkh5e.aspx

whereas this example in MSDN is not complete - http://msdn.microsoft.com/en-us/library/ms182330.aspx

akjoshi
  • 15,374
  • 13
  • 103
  • 121
  • possible duplicate of [C# Finalize/Dispose pattern](http://stackoverflow.com/questions/898828/c-finalize-dispose-pattern) – Øyvind Bråthen Dec 14 '10 at 12:18
  • @Øyvind Bråthen: Its related but it doesn't discuss this pattern in case of inheritance. – akjoshi Dec 14 '10 at 12:25
  • By the way, I noticed that this question is tagged with the wpf tag however implementing IDisposable is generally not necessary for WPF based controls since they do not inherently own resources such as a dedicated HWND as Windows Forms controls do. – jpierson Dec 14 '10 at 12:59
  • @jpierson: I agree but I am implementing this in my WPF application so tagged it, in case there is something specific/new in case of WPF. – akjoshi Dec 14 '10 at 13:14
  • I am not sure why this question is getting 'Close' votes! I am still not clear on which of the two approaches is correct, contradictory answers are given here and none of them clearly mentions pros and cons of each one? I will really appreciate if you can provide a comment after giving a Close vote. – akjoshi Dec 16 '10 at 07:20

5 Answers5

6

It's very rare for a finalizer to be useful. The documentation you link to isn't totally helpful - it offers the following rather circular advice:

Implement Finalize only on objects that require finalization

That's an excellent example of begging the question, but it's not very helpful.

In practice, the vast majority of the time you don't want a finalizer. (One of the learning curves .NET developers have to go through is discovering that in most of the places they think they need a finalizer, they don't.) You've tagged this as (amongst other things) a WPF question, and I'd say it'd almost always be a mistake to put a finalizer on a UI object. (So even if you are in one of the unusual situations that turns out to require a finalizer, that work doesn't belong anywhere near code that concerns itself with WPF.)

For most of the scenarios in which finalizers seem like they might be useful, they turn out not to be, because by the time your finalizer runs, it's already too late for it to do anything useful.

For example it's usually a bad idea to try to do anything with any of the objects your object has a reference to, because by the time your finalizer runs, those objects may already have been finalized. (.NET makes no guarantees about the order in which finalizers run, so you simply have no way of knowing whether the objects you've got references to have been finalized.) It's bad idea to invoke a method on an object whose finalizer has already been run.

If you have some way of knowing that some object definitely hasn't been finalized, then it is safe to use it, but that's a pretty unusual situation to be in. (...unless the object in question has no finalizer, and makes use of no finalizable resources itself. But in that case, it's probably not an object you'd actually need to do anything to when your own object is going away.)

The main situation in which finalizers seem useful is interop: e.g., suppose you're using P/Invoke to call some unmanaged API, and that API returns you a handle. Perhaps there's some other API you need to call to close that handle. Since that's all unmanaged stuff, the .NET GC doesn't know what those handles are, and it's your job to make sure that they get cleaned up, at which point a finalizer is reasonable...except in practice, it's almost always best to use a SafeHandle for that scenario.

In practice, the only places I've found myself using finalizers have been a) experiments designed to investigate what the GC does, and b) diagnostic code designed to discover something about how particular objects are being used in a system. Neither kind of code should end up going into production.

So the answer to whether you need "to implement a finalizer in child class too or not" is: if you need to ask, then the answer is no.

As for whether to duplicate the flag...other answers are providing contradictory advice here. The main points are 1) you do need to call the base Dispose and 2) your Dispose needs to be idempotent. (I.e., it doesn't matter if it's called once, twice, 5 times, 100 times - it shouldn't complain if it's called more than once.) You're at liberty to implement that however you like - a boolean flag is one way, but I've often found that it's enough to set certain fields to null in my Dispose method, at which point that removes any need for a separate boolean flag - you can tell that Dispose was already called because you already set those fields to null.

A lot of the guidance out there on IDisposable is extremely unhelpful, because it addresses the situation where you need a finalizer, but that's actually a very unusual case. It means that lots of people write a IDisposable implementations that are far more complex than necessary. In practice, most classes call into the category Stephen Cleary calls "level 1" in the article that jpierson linked to. And for these, you don't need all the GC.KeepAlive, GC.SuppressFinalize, and Dispose(bool) stuff that clutters up most of the examples. Life's actually much simpler most of the time, as Cleary's advice for these "level 1" types shows.

Ian Griffiths
  • 14,302
  • 2
  • 64
  • 88
  • Thanks Ian, really very useful. I have few questions 1. Can we use the base class flag(as we are calling base.Dispose and it will take care of setting the flag). 2. In case of UI Objects its enough/advisable to implement IDisposable only(no finalizer)? – akjoshi Dec 14 '10 at 13:23
  • I agree with what Ian says about not absolutely needing a boolean field. I suggested that it would be a good convention to follow but in some cases where you have a field that if null would already mean that the Dispose has occurred. – jpierson Dec 14 '10 at 16:20
  • If an object has references to other objects which aren't needed for cleanup, it shouldn't be finalizable. Rather, the stuff needed for cleanup should be encapsulated in its own finalizable object which shouldn't reference anything not needed for cleanup. – supercat Dec 15 '10 at 02:14
2

Duplicate is needed

If you don't have any clean-up in child class simply call base.Dispose() and if there are some class level clean-up, do it after a call to base.Dispose(). You need to separate state of these two classes so there should be a IsDisposed boolean for each class. This way you can add clean-up code whenever you need.

When you determine a class as IDisposable, you simply tell GC I'm taking care of it's clean-up procedure and you should SuppressFinilize on this class so GC would remove it from it's queue. Unless you call GC.SupressFinalize(this) nothing happens special to an IDisposable class. So if you implement it as I mentioned there's no need for a Finilizer since you just told GC not to finalize it.

  • So you suggest to use the pattern provided in first link(FxCop documentation)? – akjoshi Dec 14 '10 at 12:44
  • Thanks Tomas, I too think its a good way but the MSDN article says(for derived class) -"This derived class does not have a Finalize method or a Dispose method without parameters because it inherits them from the base class." What does this mean? – akjoshi Dec 14 '10 at 12:53
  • 2
    Virtual -1. You do not need a duplicate. An object is either disposing or finalizing. Base class is not a different object, it is just the base behaviour on the **same object**. It is either disposing on finalizing. – Aliostad Dec 14 '10 at 12:54
  • @akjoshi: That means no special clean-up for derived class is needed so no special implementation for `IDisposable` is needed. If we implement an empty pattern for each class its more waste of time. So don't override base class if you have no special clean-up at derived class. Base class Dispose would be called automatically. But if you override, remember to call `base.Dispose()` –  Dec 14 '10 at 12:58
  • @ Aliostad: What if we don't access to base class code. You need to separate the behavior of `disposing/finalizing` at class level not object level. –  Dec 14 '10 at 13:10
1

The correct way to implement IDisposable depends on whether you have any unmanaged resources owned by your class. The exact way to implement IDisposable is still something not all developers agree on and some like Stephen Cleary have strong opinions on the disposable paradigm in general.

see: Implementing Finalize and Dispose to Clean Up Unmanaged Resources

The documentation for IDisposable interface also explains this breifly and this article points out some of the same things but also on MSDN.

As far as whether a duplicate boolean field "isDisposed" is required in the base class. It appears that this is mainly just a useful convention that can be used when a subclass itself may add additional unmanaged resources that need to be disposed of. Since Dispose is declared virtual, calling Dispose on a subclass instance always causes that class's Dispose method to be called first which in turn calls base.Dispose as it's last step giving a chance to clear up each level in the inheritance hierarchy. So I would probably summarize this as, if your subclass has additional unmanaged resources above what is owned by the base then you will probably be best to have your own boolean isDisposed field to track it's disposal in a transactional nature inside it's Dispose method but as Ian mentions in his answer, there are other ways to represent an already-disposed state.

jpierson
  • 16,435
  • 14
  • 105
  • 149
  • Thanks for the links jpierson, looks intresting. – akjoshi Dec 14 '10 at 12:58
  • 1
    A base-class IsDisposed flag can be useful to derived classes if all dispose operations are wrapped by the same non-overridden class which does an Interlocked.Exchange on it to ensure there are no redundant dispose operations. As Microsoft's suggested implementation handles it, however, the base-level IsDisposed flag can't really be used by child classes. – supercat Dec 15 '10 at 02:19
0

1) No need to duplicate

2) Implementing a finalizer will help to dispose items that are not explicitly disposed. But is not guaranteed. It is a good practice to do.

Aliostad
  • 80,612
  • 21
  • 160
  • 208
0

Only implement a finalizer if an object holds information about stuff needing cleanup, and this information is in some form other than Object references to other objects needing cleanup (e.g. a file handle stored as an Int32). If a class implements a finalizer, it should not hold strong Object references to any other objects which are not required for cleanup. If it would hold other references, the portion responsible for cleanup should be split off into its own object with a finalizer, and the main object should hold a reference to that. The main object should then not have a finalizer.

Derived classes should only have finalizers if the purpose of the base class was to support one. If the purpose of a class doesn't center around a finalizer, there's not much point allowing a derived class to add one, since derived classes almost certainly shouldn't (even if they need to add unmanaged resources, they should put the resources in their own class and just hold a reference to it).

supercat
  • 77,689
  • 9
  • 166
  • 211