2

I've had to implement Dispose() functionality recently, and have come across 1 line method, 2 line methods and more comprehensive methods.

A 1 line method/functionwould simply call something like "context.Dispose", but the method I picked up was this:

    bool _disposed = false;

    public void Dispose(bool disposing)
    {
        if (!_disposed && disposing)
        {
            _context.Dispose();
        }
        _disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

Is this syntax merely to stop Dispose() being called more than once?

dotnetnoob
  • 10,783
  • 20
  • 57
  • 103
  • 1
    You forgot the finalizer. Also make Dispose(bool) virtual. – Maarten Aug 26 '12 at 13:01
  • 2
    This can help: [Implementing IDisposable and the Dispose Pattern Properly](http://www.codeproject.com/Articles/15360/Implementing-IDisposable-and-the-Dispose-Pattern-P) – Şafak Gür Aug 26 '12 at 13:04
  • That's the legacy dispose pattern. IMO there is little reason to use it anymore. – CodesInChaos Aug 26 '12 at 13:10
  • @CodesInChaos - If thats the case what should be used in its place? – dotnetnoob Aug 26 '12 at 13:24
  • Depends on the situation. A `SafeHandle` as the direct owner of the unmanaged resources, and a simple `Dispose` method without finalizer as indirect owner. – CodesInChaos Aug 26 '12 at 13:26
  • @CodesInChaos: *You* not having seen the need to use it lately doesn't mean it's not needed at all any more. – Johann Gerell Aug 26 '12 at 14:38
  • @Maarten Knee-jerk addition of a finalizer simply to call Dispose(false) is not usually a good thing. See http://www.bluebytesoftware.com/blog/2011/11/12/ABriefNoteOnObjectMortality.aspx for details on the drawbacks of having a finalizer that doesn't result in freeing unmanaged resources – Peter Ritchie Aug 26 '12 at 14:39

3 Answers3

4

What you've posted is partially the Dispose Pattern. As someone pointed out there should be a corresponding Dispose(false) in a finalizer ("destructor"). The finalizer should be used to dispose of unmanaged resources. If you don't have unmanaged resources to deal with (i.e. you don't have anything to do when disposing is false), you don't need a Dispose(false) and thus don't need a finalizer. This means thatDispose(true) is the only path, so you don't need Dispose (bool) (and thus don't need to implement the Dispose Pattern) and can move it's body into Dispose (and remove the check for disposing) and just implement Dispose. For example:

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

Classes that don't implement their own finalizer (destructor) are not put on the finalizer list so there's no need to call GC.SuppressFinalize.

In general, this is enough if you're creating a class. But, sometimes you can derive from classes that implement this pattern. In which case you should implement support for it in your class (override Dispose(bool) and do the disposing check and Dispose of any managed resources). Since the base class implements IDisposable and calls a virtual Dispose(bool) in its Dispose(), you don't need to implement Dispose() yourself, but you have to call the base's Dispose(bool) in your Dispose(bool). For example:

protected override void Dispose(bool disposing)
{
    if(disposing) _context.Dispose();
    base.Dispose(disposing);
}

If you're calling into the base and it's implemented the Dispose Pattern, then you also don't need to call GC.SuppressFinalize() because it's already doing it.

You can do the whole disposed thing if you want; I find that it hides multi-dispose bugs though.

Peter Ritchie
  • 35,463
  • 9
  • 80
  • 98
  • Peter are you also saying I should ignore GC.SupressFinalize() too? – dotnetnoob Aug 26 '12 at 14:46
  • If you don't have a finalizer, there's nothing to suppress. I.e. C# classes without a finalizer (destructor) are not put in the finalization list, and don't need to be suppressed. – Peter Ritchie Aug 26 '12 at 14:47
  • Peter, thanks for your help - this is all very new, so clear explanations are very welcome. – dotnetnoob Aug 27 '12 at 15:29
2

That is only part of the pattern. The other part missing here is that Dispose(false) would be called by a Finalizer.

The _disposed state flag can also be used to check and throw ObjectDisposedExceptions in your methods.

The full pattern is here

Jon Skeet provides good information here, and IMO this pattern is overkill for most situations unless you also have unmanaged resources. If not, just dispose of your managed resources and GC.SuppressFinalize in the Dispose() interface implementation. Use the _disposed flag only if you intend throwing ObjectDisposedExceptions.

Community
  • 1
  • 1
StuartLC
  • 104,537
  • 17
  • 209
  • 285
  • Jon doesn't really go into a lot of detail there other than "I don't follow this pattern often". Joe Duffy goes into some detail on finalization and the consequences of having a finalizer that doesn't free unmanaged resources here: http://www.bluebytesoftware.com/blog/2011/11/12/ABriefNoteOnObjectMortality.aspx – Peter Ritchie Aug 26 '12 at 14:37
1

I use the following two forms of dispose based on the class need:

Method 1 (For a class with managed and un-managed resources or with derived classes):

class ClassHavingManagedAndUnManagedCode : IDiposable
    {
        private volatile bool _disposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    //Do managed disposing here.
                }

                //Do unmanaged disposing here.
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);

            _disposed = true;
        }

        ~ClassHavingManagedAndUnManagedCode()
        {
            Dispose(false);
        }
    }

Method 2 (For a class with only managed resource / sealed class / class that has not child classes):

    class ClassHavingOnlyManagedCode  : IDiposable
    {
        private volatile bool _disposed = false;

        public void Dispose()
        {
            if (!_disposed)
            {
                //Dispose managed objects.
                _disposed = true;
            }
        }
    }

Any child classes of ClassHavingManagedAndUnManagedCode should just follow the protected dispose method pattern and call the base.Dispose at the end of the Dispose method.

Also guard all public methods (atleast ones that are using the members that are disposed) using a method /check that throws ObjectDisposedException if the class instance is already disposed.

FxCop will always ask you to implement the ClassHavingManagedAndUnManagedCode form of Dispose even if you do not have any unmanaged resources.

Ganesh R.
  • 4,337
  • 3
  • 30
  • 46
  • If you don't have an unmanaged resources you don't need the finalizer. In fact, by having it you've increased the stress on the GC. An object cannot be collected until the finalizer has run so the object is "kept alive" until the system has time to call the finalizer. See my answer for detail on not needing the finalizer and it's consequence on `Dispose(bool)` See also http://www.bluebytesoftware.com/blog/2011/11/12/ABriefNoteOnObjectMortality.aspx – Peter Ritchie Aug 26 '12 at 14:35
  • @PeterRitchie I agree with you that we do not need the finalizer if we do not have unmanaged code. Hence I have given two different variants of dispose pattern, one for class with managed code and one without. Also if we do a GC.SupressFinalize, I am not sure if we are adding any stress in GC. – Ganesh R. Aug 26 '12 at 14:50
  • You have a bug in your method 2 code, you don't dispose of anything unless Dispose is called twice `if(_disposed) {/* dispose managed objects */} _disposed = true;` – Peter Ritchie Aug 26 '12 at 14:54
  • If you do *all* the cleanup in Dispose(bool) when `disposing` is true **and** you have a finalizer (destructor) then you should have a call to GC.SuppressFinalize (either in Dispose() or Dispose(bool) when `disposing` is `true`) to reduce the stress on the GC (well, the finalizer--but, without SuppressFinalize you increase the risk of objects staying alive to gen2 which stresses the GC) – Peter Ritchie Aug 26 '12 at 14:59
  • @Ganesh - thanks for th input it was very much appreciated. I've accepted Peter's answer as it helped me understand a little more about Dispose() but I've voted your answer up as it was particularly useful and will be used again in the future. – dotnetnoob Aug 27 '12 at 15:28
  • Is there any scenario in which a class with unmanaged resources requiring `Finalize`-based cleanup should inherit from a class whose purpose does not center around such cleanup? In every case I can think of, it would be better to wrap the unmanaged resource in its own finalizable object (which could be a private class nested within the type that uses it), so the containing class would not need to worry about cleanup finalization. – supercat Aug 27 '12 at 19:48