开发者

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

开发者 https://www.devze.com 2023-02-17 00:29 出处:网络
Should implementations of IDisposable make Dispose() safe to call multiple times? Or the opposite? What approach to most .NET Framework classes take?

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;
    }

    // Vers开发者_运维问答us 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.


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.


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.


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.


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);
    }      
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号