11

I use a default IDisposable implementation template (pattern) for my code.

snippet:

public void Dispose()
{
    Dispose(true);

    GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool isDisposing)
{
    if (!this.disposed)
    {
        if (isDisposing)
        {
            //cleanup managed resources
        }

        //cleanup unmanaged resources

        this.disposed = true;
    }
}

My question: why is the call "GC.SuppressFinalize(this)" in the Dispose public method? I would place "GC.SuppressFinalize(this)" in the "if (isDisposing)" section of the protected method, after disposing managed resources.

Like this:

protected virtual void Dispose(bool isDisposing)
{
    if (!this.disposed)
    {
       if (isDisposing)
       {
           //cleanup managed resources

           GC.SuppressFinalize(this);
       }

       //cleanup unmanaged resources

       this.disposed = true;
    }
}
akjoshi
  • 15,374
  • 13
  • 103
  • 121
Patrick Peters
  • 9,456
  • 7
  • 57
  • 106
  • 1
    As Stackoverflow supports tagging, you should not prefix your message title with [.NET] ;-) – Fabian Vilers Mar 03 '09 at 09:33
  • Similar Question - http://stackoverflow.com/questions/2605412/why-should-we-call-suppressfinalize-when-we-dont-have-a-destructor – akjoshi Apr 10 '12 at 12:21

5 Answers5

12

I suppose its a clear case of Template Design pattern.

Your abstract class is Designed to take care of all important/necessary tasks required (Here, GC.SuppressFinalize(this)), and allowing a derived class to override only some part of the code.

There are 2 cases here:
Snippet 1, SuppressFinalize, in Dispose
Snippet 2, SuppressFinalize, in Dispose(true)

Here, Snippet 1, makes sure that GC.SuppressFinalize is always executed. While snippet 2, leaves the execution of GC.SuppressFinalize at the mercy of derived class.

So, by putting GC.SuppressFinalize, in Dispose method, you as a designer of your class will always make sure that irrespective of whatever code written by derived classes, GC.SuppressFinalize will be executed.

This is only the benefit of writing SuppressFinalize in Dispose rather then Dispose(true).

NileshChauhan
  • 5,469
  • 2
  • 29
  • 43
  • When the derived class omits the base dispose call then more resources are not cleaned up... – Patrick Peters Mar 03 '09 at 12:13
  • I think it is the responsibility of the derived class to implement the base calls correctly, so I still prefer my solution. – Patrick Peters Mar 06 '09 at 09:09
  • 1
    @PatrickPeters: If a derived class has resources which need to be cleaned up after those of the parent, `GC.SuppressFinalize` should not be called until that derived class has finished its cleanup. Putting the `SuppressFinalize` call within the virtual method would result in its being called early. – supercat Apr 12 '12 at 14:50
6

The Dispose(bool isDisposing) method isn't part of the IDisposable interface.

You would normally call Dispose(true) from your Dispose method, and call Dispose(false) from your finalizer, as a fallback in the case where the object hasn't already been disposed.

Calling SuppressFinalize tells the GC that there's no need to call your object's finalizer, presumably because all your cleanup was done when Dispose was called.

If you don't have a finalizer on your class, then you don't need to call SuppressFinalize at all, since there's no finalizer to suppress!

Joe Duffy has some great guidelines on disposal, finalization, garbage collection etc.

LukeH
  • 263,068
  • 57
  • 365
  • 409
  • Thanks for the info, but is this on-topic ? Look at my specific question, it's about the location of the suppress call. – Patrick Peters Mar 03 '09 at 10:58
  • The examples in your question don't have finalizers, and if that's also the case in your "real" code then calling SuppressFinalize is irrelevant/unnecessary wherever you do it, because there's no finalizer to suppress. – LukeH Mar 03 '09 at 11:01
  • @Henk, Absolutely right, I should've made that clear in my answer. The point I'm trying to make is that *where* you call SuppressFinalize is *completely irrelevant* if your class doesn't have a finalizer in the first place! – LukeH Mar 03 '09 at 11:52
  • @Henk, Not necessarily. Finalizers are expensive. You should only implement a finalizer if you absolutely need to, and you shouldn't need to unless your class handles unmanaged resources directly. – LukeH Mar 03 '09 at 12:24
  • The example I used here is with unmanaged resources in mind. When using unmanaged resources you must use a finalizer to cleanup the unmanaged stuff when the Dispose() call hasn't been used. – Patrick Peters Mar 04 '09 at 11:43
1

I think either layout could have been chosen, but probably they wanted to emphasize "put all deallocation code in this method" in the protected Dispose method, so they put the other artifact of disposing (Suppressing finalization) elsewhere.

Also, suppose a derived class had another reason for calling the protected Dispose method, but did still want finalization to occur (for whatever imagined reason, I don't know).

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
  • But what if I call the public Dispose of several times (because that should be possible according the guidelines), the suppress call is also called several times. That shouldn't be the case... In my code example it will be called just once. – Patrick Peters Mar 03 '09 at 10:14
  • Although Dispose *can* be called several times, it's generally a symptom of problems elsewhere in the codebase - two or more pieces of code beliefing that they control the life of the object. Similarly, GC.SuppressFinalize *can* be called multiple times. – Damien_The_Unbeliever Mar 03 '09 at 10:53
  • Though it could be flaw in code when multiple calls of Dispose is called, it should be programmed defensively so that it can handle it. – Patrick Peters Mar 03 '09 at 11:00
  • Calling SuppressFinalize multiple times is not a problem. It is a sign of problems elswhere though. – H H Mar 03 '09 at 12:01
1

Cause .Dispose is when managed code (your code) disposes of the object thereby opting out of finalisation. People usually create another route into Dispose(bool disposing) via a finaliser and the call wouldn't make any sense for the finaliser to make.

Quibblesome
  • 25,225
  • 10
  • 61
  • 100
0

The idea is that your cleanup code should only be called once. However there are two points of entry: the Dispose method and object finalizers. When Dispose is called, you opt-out of finalization so that your cleanup code is only called once. The code here might illustrate it better.

Quote:

// NOTE: Leave out the finalizer altogether if this class doesn't 
// own unmanaged resources itself, but leave the other methods
// exactly as they are. 
Ken Browning
  • 28,693
  • 6
  • 56
  • 68
  • My example is an complex base class structure with IDisposable. I have searched many scenario's with IDisposable implementations (templates), but didn't find a correct base-class -> derived class example. – Patrick Peters Mar 03 '09 at 10:38
  • it is not a complete example @ MSDN: MSDN shows only the base-class implementation and not a base-class/derived class example. – Patrick Peters Mar 05 '09 at 06:16