Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does a stream dispose when its writer is disposed?

Consider the following code:

using (var ms = new MemoryStream())
{
    using(var writer = BinaryWriter(ms))
    {
        writer.Write(/*something*/);
        writer.Flush();
    }

    Assert.That(ms.Length > 0); // Throws ObjectDisposedException
}

On the one hand, a disposable object should dispose of it's resources; I get that, but on the other hand, the object didn't create and doesn't own this resource, it was provided -> calling code should take responsibility for it... no?

I can't think of any other situations like this, but is it a consistent pattern in the framework for any class receiving disposable objects to dispose of them on its own dispose?

like image 424
Steven Evers Avatar asked Dec 05 '10 10:12

Steven Evers


2 Answers

There is an implicit assumption that you will only have one writer per stream, so the writer assumes ownership of the stream for convenience - you then obly have one thing to clean up.

But I agree; this is not always true, and often inconvenient. Some implementations (DeflateStream, GZipStream, for example) allow you to choose. Otherwise the only real option is to inject a dummy stream between the writer and the underlying stream; IIRC there is a NonClosingStreamWrapper in Jon Skeet's "MiscUtil" library that does exactly this: http://www.yoda.arachsys.com/csharp/miscutil/

Usage would be something like:

using (var ms = new MemoryStream())
{
    using(var noClose = new NonClosingStreamWrapper(ms))
    using(var writer = BinaryWriter(noClose))
    {
        writer.Write(/*something*/);
        writer.Flush();
    }

    Assert.That(ms.Length > 0);
}
like image 138
Marc Gravell Avatar answered Oct 21 '22 03:10

Marc Gravell


I totally agree with you. This is not consistent behavior but it is how it has been implemented. There are comments at the end of the documentation about this behavior which is not very intuitive. All stream writers just take ownership of the underlying stream and dispose it. Personally I always nest my using statement like this:

using (var ms = new MemoryStream())
using(var writer = BinaryWriter(ms))
{
    writer.Write(/*something*/);
}

so that a code like the one you put in the Assert shouldn't be written.

like image 43
Darin Dimitrov Avatar answered Oct 21 '22 04:10

Darin Dimitrov