2

Suppose you have the following inheritance chain:

class A : IDisposable
{
    public void Dispose()...
    protected virtual void Dispose(bool disposing)...
}

class B : A
{
    // Virtual or Override for B?
}

class C : B
{
    protected override void Dispose(bool disposing)...
}

If A, B, and C each have their own private IDisposable resources, how should B declare Dispose(bool)?

Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
Didaxis
  • 8,486
  • 7
  • 52
  • 89
  • 1
    Is it possible to declare two void Dispose with no params in a single class? – Alex Aug 14 '13 at 14:20
  • 3
    You just call `base.Dispose()` and free own for `B` resources. What is the problem? – Sinatr Aug 14 '13 at 14:21
  • 1
    The pattern actually calls for `protected virtual void Dispose(bool disposing)` so your question is borked before you started. – spender Aug 14 '13 at 14:22

2 Answers2

4

You should override, not hide:

class A : IDisposable
{
    public void Dispose() {
      Dispose(true);
      GC.SuppressFinalize(this); // <- May be excluded
    }

    protected virtual void Dispose(Boolean disposing)... // <- "disposing" recommended by Microsoft
}

class B : A
{
    protected override void Dispose(Boolean disposing) {
      // Dispose here all private resources of B
      ...
      base.Dispose(disposing);
    }
}

class C : B
{
    protected override void Dispose(Boolean disposing) {
      // Dispose here all private resources of C
      ...
      base.Dispose(disposing);
    }
}
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • Marking this one as answer because you address the override part, and the fact that `base.Dispose()` should be called. I feel like a dummy for asking this question now, i knew that! – Didaxis Aug 14 '13 at 14:33
  • Would you recommend to add a destructor within each of these classes (and calling this.Dispose(false);)? What if class A and B were abstract classes, would your solution be any different? – progLearner Feb 09 '21 at 13:26
  • @progLearner: c# doen't have *destructor*, but *finalizer*; when you implement finalizer, please, note that order in which finalizeres are executed is *no specified* so you should not use *reference* type fields. So, probably, the only relevant case for `~C()` is when you acquire the resource as low level structure (pointer `IntPtr`). It doesn't matter if `A` or `B` or both of them are `abstract` classes or not – Dmitry Bychenko Feb 09 '21 at 13:49
  • Thanks. I am asking about the finaliser, because I want to make sure Dispose() is called by my client application when shut down. Is that not what the finalizer is supposed to be for? – progLearner Feb 09 '21 at 13:52
  • 1
    @progLearner: when *application* (i.e. *process*) shuts down, OS will release all the resources acquired - opened files, streams etc.; if you want to ensure that some *special* resources (like rdbms connections) are properly released (say, commited and closed) you can try use `Application.ApplicationExit` event and the like. Please, note, that *finalizer* can well be *not* executed at all – Dmitry Bychenko Feb 09 '21 at 14:21
3

It should declare it using override. If it declares using virtual instead of override, then that would hide the A.Dispose.

By the way, you cannot declare two Dispose methods within A, both with no parameters (they cannot differentiate by return type or by accessors).

Eren Ersönmez
  • 38,383
  • 7
  • 71
  • 92