1

I searched and did not find the exact answer. I'm learning the correct way of Implementing Dispose. I am wondering why need the 2 bools.

  1. Why need disposing? Only the destructor calls Dispose (false), so why destructor not force release managed resources?
  2. Why need disposed? If this object is already disposed, how could the Dispose method be called? Could you tell a scenario when the Dispose is called and disposed is true?
Lei Yang
  • 3,970
  • 6
  • 38
  • 59
  • 1
    have you checked out http://stackoverflow.com/questions/538060/proper-use-of-the-idisposable-interface/538238#538238 ? – Shazi Mar 10 '16 at 09:15
  • @Shazi thanks, I'll read it in detail. – Lei Yang Mar 10 '16 at 09:41
  • If the *disposing* argument is false then the object was not disposed. It is the finalizer (aka destructor) that ran. That matters a lot, it means that you cannot dispose any objects stored in fields, they might have already been finalized. You need *disposed* for safety, client code may call Dispose more than once. Writing your own finalizer and implementing the disposable pattern has a very desirable trait, it is wrong 99.9% of the time. Framework classes need to do this, not you. – Hans Passant Mar 10 '16 at 09:48

2 Answers2

1

The disposing boolean is there to indicate where Dispose was called from. Was it explicitly called via YourObject.Dispose or a using statement, or was it implicitly called from the finalizer thread.

This differentiation is needed because when Dispose is ran from the finalizer thread, there is no guarantee that any managed objects are still alive in object, thus restricting dispose only to to unmanaged resources owned by the type.

The disposed boolean is there to flag that the object has already been disposed. Say, for example, one does dispose the object, but the implementation lacks GC.SuppressFinalize(this). Even though the object is disposed, it would still run (again) once it's finalizer executes, and attempt to free those unmanaged resources again, where they have already been released.

The example in the documentation you provided explains this nicely:

protected virtual void Dispose(bool disposing)
{
    if (!disposed)
    {
        if (disposing)
        {
            // Free other state (managed objects).
        }

        // Free your own state (unmanaged objects).
        // Set large fields to null.
        disposed = true;
    }
}
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
1

For the second question: the Dispose() method should be callable twice without problems (see 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.Instance methods other than Dispose can throw an ObjectDisposedException when resources are already disposed.

A common case is when a Stream object is passed to another Stream object that takes "ownership":

using (var ms = new MemoryStream())
{
    using (var sw = new StreamWriter(ms))
    //using (var sw = new StreamWriter(zip, Encoding.UTF8, 4096, true))
    {

    }

    // false: ms has already been disposed
    bool canWrite = ms.CanWrite;
}

The StreamWriter normally takes ownership on the underlying stream (in this case ms), so that when the Dispose() of the StreamWriter is called so is the Dispose() of the MemoryStream... But note that even the MemoryStream is in a using block, so its Dispose() will be called again.

There is no problem here, because the Dispose() of the various Stream classes are correctly implemented. If you want to avoid this double Dispose(), nearly all the Stream classes have an overload that tells them if they must take ownership on the underlying Stream (see the commented row... The argument is called leaveOpen, so by setting it to true the StreamWriter won't Dispose() the underlying stream)

xanatos
  • 109,618
  • 12
  • 197
  • 280