Should IDisposable.Dispose() be made safe to call multiple times?

C#.NetIdisposable

C# Problem Overview


Should implementations of IDisposable make Dispose() safe to call multiple times? Or the opposite? What approach to most .NET Framework classes take?

Specifically, is it safe to call System.Data.Linq.DataContext.Dispose() multiple times?

The reason I ask is because I am wondering if this extra protection is necessary:

public override void Dispose(bool disposing)
{
    // Extra protection...
    if (this.obj != null)
    {
        this.obj.Dispose();
        this.obj = null;
    }

    // Versus simply...
    this.obj.Dispose();

    base.Dispose(disposing);
}

when disposing IDisposable members of a class, or whether I should just call this.obj.Dispose() without concern for whether it has been previously called.

C# Solutions


Solution 1 - C#

You should be safe to call it more than once, though you should probably avoid it if you can.

From the MSDN page on IDisposable.Dispose():

> If an object's Dispose method is called more than once, the object must ignore all calls after the first one. The object must not throw an exception if its Dispose method is called multiple times.

Solution 2 - C#

Yes, your implementations of IDisposable.Dispose() should tolerate being called multiple times. After the first call to Dispose(), all other calls can just return immediately.

I would prefer the first part of your code example, to dispose and null the local variables as you go.

Be aware that your .Dispose() may be called multiple times even if you implement Dispose and null patterns in your code. If multiple consumers hold a reference to the same disposable object, then that object's Dispose will probably be called multiple times as those consumers drop their references to it.

Solution 3 - C#

Objects should be tolerant to having Dispose called more than once, since--especially in the presence of exceptions--it may be difficult for cleanup code to know for certain which things have been cleaned up and which have not. Nulling out IDisposable fields as they are cleaned up (and being tolerant of ones that are already null) will make it easier to avoid redundant calls to Dispose, but it doesn't really cost anything to make objects tolerate multiple disposal, and it helps to avoid ickiness in some Exception-throwing situations.

Solution 4 - C#

If an object is disposed you shouldn't be disposing of it a second time.This helps you to not prolong the life of the object in the Garbage Collector.

A pattern I use normally is this.

// A base class that implements IDisposable.
// By implementing IDisposable, you are announcing that
// instances of this type allocate scarce resources.
public class BaseClass: IDisposable
{
    /// <summary>
    /// A value indicating whether this instance of the given entity has 
    /// been disposed.
    /// </summary>
    /// <value>
    /// <see langword="true"/> if this instance has been disposed; otherwise, 
    /// <see langword="false"/>.
    /// </value>
    /// <remarks>
    /// If the entity is disposed, it must not be disposed a second
    /// time. The isDisposed field is set the first time the entity
    /// is disposed. If the isDisposed field is true, then the Dispose()
    /// method will not dispose again. This help not to prolong the entity's
    /// life in the Garbage Collector.
    /// </remarks>
    private bool isDisposed;

   /// <summary>
    /// Disposes the object and frees resources for the Garbage Collector.
    /// </summary>
    public void Dispose()
    {
        this.Dispose(true);

        // This object will be cleaned up by the Dispose method.
        // Therefore, you should call GC.SupressFinalize to
        // take this object off the finalization queue 
        // and prevent finalization code for this object
        // from executing a second time.
        GC.SuppressFinalize(this);
    }

    /// <summary>
    /// Disposes the object and frees resources for the Garbage Collector.
    /// </summary>
    /// <param name="disposing">If true, the object gets disposed.</param>
    protected virtual void Dispose(bool disposing)
    {
        if (this.isDisposed)
        {
            return;
        }

        if (disposing)
        {
            // Dispose of any managed resources here.

        }
        
        // Call the appropriate methods to clean up
        // unmanaged resources here.
        // Note disposing is done.
        this.isDisposed = true;

    }

    // Use C# destructor syntax for finalization code.
    // This destructor will run only if the Dispose method
    // does not get called.
    // It gives your base class the opportunity to finalize.
    // Do not provide destructors in types derived from this class.
    ~BaseClass()
    {
        // Do not re-create Dispose clean-up code here.
        // Calling Dispose(false) is optimal in terms of
        // readability and maintainability.
        Dispose(false);
    }      
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJake PetroulesView Question on Stackoverflow
Solution 1 - C#Adam RobinsonView Answer on Stackoverflow
Solution 2 - C#dthorpeView Answer on Stackoverflow
Solution 3 - C#supercatView Answer on Stackoverflow
Solution 4 - C#James SouthView Answer on Stackoverflow