Why does a stream dispose when its writer is disposed? - c#

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?

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

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.

The right thing to have done would have been to have a constructor parameter for the streamwriter indicate whether the stream should be disposed when the constructor is. Given that Microsoft didn't do that, it may be good to define a NonDisposingStream(Of T as Stream) class which wraps a stream but does not pass a Dispose call to the wrapped stream. One could then pass a new NonDisposingStream to the constructor of a StreamWriter, and the underlying stream would be safe from disposal (it would be necessary, of course, to dispose of the stream yourself).
Having an object which can dispose of a passed-in object is useful. While such behavior doesn't coincide with the usual pattern of an object's creator handling its disposal, there are often situations where an object's creator will have no idea how long the object will actually be needed. For example, a method may be expected to create a new StreamWriter which uses a new Stream. The owner of the StreamWriter will know when it should be disposed, but may not know of the inner stream's existence. The creator of the inner stream will have no idea how long the outer StreamWriter will be used. Having ownership of the stream "handed off" to the StreamWriter solves the disposal problem in that particular (common) case.

I propose this wrapper class:
public class BetterStreamWriter : StreamWriter
{
private readonly bool _itShouldDisposeStream;
public BetterStreamWriter(string filepath)
:base(filepath)
{
_itShouldDisposeStream = true;
}
public BetterStreamWriter(Stream stream)
: base(stream)
{
_itShouldDisposeStream = false;
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing && _itShouldDisposeStream);
}
}
Objects should not dispose stuff they didn't instantiate. If it's a file stream writer, it should dispose. If it's an external stream, it shouldn't.
Shouldn't have implemented opening file path in the first place. This violate single responsibility principle as the object both manages writing and lifetime of the file.

Related

How to apply using-pattern with System.Func?

Usually I use a memory stream with the well known using pattern.
using(var mem = new MemoryStream(blob))
{
foo(mem);
}
No imagine a function bar(Func<Stream>) defined in a client library that I have to use. I could call it like this
bar(() => new MemoryStream(blob));
but then nobody is disposing the stream properly. How to work around it? Should Func be used with IDisposable types at all?
It seems like a poorly designed library.
If you know for a fact that the library does not dispose of the stream and it doesn't hold the Func<Stream> for later use, then you can do this:
using(var mem = new MemoryStream(blob))
{
bar(() => mem);
}

Disposing MemoryStreams and GZipStreams

I want to compress a ProtoBuffer object on serialisation and decompress on deserialisation. Unfortunatly, C# stdlib offers only compression routines that work on streams rather than on byte[], that makes it a bit unesseray more verbose than a function call. My Code so far:
class MyObject{
public string P1 {get; set;}
public string P2 {get; set;}
// ...
public byte[] Serialize(){
var builder = new BinaryFormat.MyObject.Builder();
builder.SetP1(P1);
builder.SetP2(P2);
// ...
// object is now build, let's compress it.
var ms = new MemoryStream();
// Without this using, the serialisatoin/deserialisation Tests fail
using (var gz = new GZipStream(ms, CompressionMode.Compress))
{
builder.Build().WriteTo(gz);
}
return ms.ToArray();
}
public void Deserialize(byte[] data)
{
var ms = new MemoryStream();
// Here, Tests work, even when the "using" is left out, like this:
(new GZipStream(new MemoryStream(data), CompressionMode.Decompress)).CopyTo(ms);
var msg = BinaryFormat.MachineInfo.ParseFrom(ms.ToArray());
P1 = msg.P1;
P2 = msg.P2;
// ...
}
}
When dealing with streams, it seems one has to manually take care of the disposal of the objects. I wonder why that is, I'd expect GZipStream to be fully managed Code. And I wonder If Deserialize works only by accident and if I should dispose the MemoryStreams aswell.
I know I could probably solve this problem by simply using a thrid party compression library, but that's somewhat besides the point of this question.
GZipStream needs to be disposed so it flushes it's final blocks of compression out of its buffer to its underlying stream, it also calls dispose on the stream you passed in unless you use the overload that takes in a bool and you pass in false.
If you where using the overload that did not dispose of the MemoryStream it is not as critical to have the MemoryStream be disposed because it is not writing its internall buffer anywhere. The only thing it does is set some flags and set a Task object null so it can be GCed sooner if the stream lifetime is longer than the dispose point.
protected override void Dispose(bool disposing)
{
try {
if (disposing) {
_isOpen = false;
_writable = false;
_expandable = false;
// Don't set buffer to null - allow TryGetBuffer, GetBuffer & ToArray to work.
#if FEATURE_ASYNC_IO
_lastReadTask = null;
#endif
}
}
finally {
// Call base.Close() to cleanup async IO resources
base.Dispose(disposing);
}
}
Also, although the comment says "Call base.Close() to cleanup async IO resources" the base dispose function from the Stream class does nothing at all.
protected virtual void Dispose(bool disposing)
{
// Note: Never change this to call other virtual methods on Stream
// like Write, since the state on subclasses has already been
// torn down. This is the last code to run on cleanup for a stream.
}
All that being said, when decompressing a GZipStream you can likely get away with not disposing it for the same reason as not disposing the MemoryStream, when decompressing it does not buffer bytes anywhere so there is no need to flush any buffers.

Do i need to Dispose Stream when i Pass it to IDisposable class?

I wrote a piece of code. I want to make sure that I am Disposing an Object in right way.
I have a Disposable Class like this
Which is used to read some data from unmanaged resource.
class MyFileReader : IDisposable
{
private readonly FileStream _stream;
public MyFileReader(FileStream stream)
{
_stream = stream;
}
public void Dispose()
{
_stream.Dispose();
}
}
Currently in my program I Dispose objects like this.
using (FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
{
using (MyFileReader reader = new MyFileReader(stream))
{
//...
}
}
This seems ok to me. later I have noticed That Classes are passed by reference so maybe if I dispose one of them there is no need to dispose the other one.
My question is Can i Do Something like this?
using (FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
{
MyFileReader reader = new MyFileReader(stream);
// Remove IDisposable from MyFileReader and stream will close after using.
}
Or this one?
FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
// stream will close after using.
using (MyFileReader reader = new MyFileReader(stream))
{
//...
}
Yes, you can write code like that.
But, no, you should not do that.
Your class looks like on of XxxxReader classes that by convention own the stream they read from. As result your MyFileReader class is expected to dispose the inner stream. You also normally expected to dispose each and every disposable object when you know that such object's lifetime is over.
Note that sometimes it lead to multiple Dispose calls on some objects (which should be expected by implementations of IDisposable). While it may sometimes lead to Code Analysis warning it is better than missing Dispose calls if one routinely tries to "optimize" number of calls to Dispose by skipping some.
Alternative approach is to expose method that reads content which by convention is not expected to take ownership of stream/reader like:
using(stream....)
{
var result = MyFileReader.ReadFrom(stream);
}
If MyFileReader is accessing some unmanaged resource and you need the Disponse method to be called explicitly after this code block, then you have to stick with your current implementation.
In the second implementation, the Dispose method will not be called for the MyFileReader object. (until you probably call it in the destructor which you don't know when that would be called)
If you do not like the nested using, then you can probably go with the second alternative and in the Dispose() method implementation of MyFileReader class, explicitly dispose the Stream. If this stream is only use by MyFileReader, then this is a good practice to have MyFileReader manage its lifecycle and dispose it.
Many framework stream-wrapping classes have constructor overloads with leaveOpen parameter that controls stream disposing behavior.
Examples include StreamReader, BinaryReader, GZipStream.
There is also property approach, SharpZipLib example:
using (var zip = new ZipInputStream(stream) { IsStreamOwner = false }) { ... }

Why does visual studio code analysis warn me that this object can be disposed twice in this code (when it can't)

Code is:
using (MemoryStream memorystream = new MemoryStream(bytes))
{
using (BinaryWriter writer = new BinaryWriter(memorystream))
{
writer.Write((double)100.0);
}
return memorystream.ToArray();
}
Isn't the above code appropriate to properly dispose of both object?
Is the code analysis at all useful? Other than garbage information about variables names and namespaces it seems to complain about a lot of things that are not reality. I am really thinking that maybe it is useful and I am just missing the point.
OKAY to address concerns whether the MemoryStream is disposed of or not (its not) here is an example where the VS code analysis gives me the exact same warning. Clearly nothing is getting disposed of here
public class MyClass : IDisposable
{
public void DoSomethingElse()
{
}
#region IDisposable Members
public void Dispose()
{
throw new NotImplementedException();
}
#endregion
}
public class MyOtherClass : IDisposable
{
public MyOtherClass(MyClass mc)
{
}
public void DoSomething() { }
}
public void Foo()
{
using (MyClass mc = new MyClass())
{
using (MyOtherClass otherclass = new MyOtherClass(mc))
{
otherclass.DoSomething();
}
mc.DoSomethingElse();
}
}
On "If the stream were disposed then how can I call memorystream.ToArray()" part of the question:
MemeoryStream.Dispose does not release internal buffer. The only thing that it does is blocking all Stream methods (like Read) by throwing "Object Disposed" exception. I.e. following code is perfectly valid (usually similar code accessing lower level storage can be written for other other Stream objects that manage some sort of storage):
MemoryStream memoryStream = new MemoryStream();
using (memoryStream)
{
// write something to the stream
}
// Note memoryStream.Write will fail here with an exception,
// only calls to get storage (ToArray and GetBuffer) make sense at this point.
var data = memoryStream.ToArray();
BinaryWriter does not dispose the MemoryStream. YOU NEED TO DISPOSE OF IT. Get the results of .ToArray in a variable, then dispose the MemoryStream, then return the result. Or use a try/finally to dispose of the MemoryStream.
If I were to guess I would say that the logic of the analysis rule is identifying a possiblity that goes someting like this:
"You are passing a disposable object into the constructor of another disposable object (thus semantically implying a transfer of ownership). If ownership is truly being trasnsferred to the second object, it's likely that it will dispose of the object passed to its constructor in its own Dispose method but you're disposing of it as well."
Your second example proves that it is not actually analysing whether or not the second object takes ownership of and disposes the first, but rather this rule is saying this pattern has some semantic ambiguity, as the code responsible for disposal of the first object is no longer clear.
The dispose pattern has all of the inherent pitfalls of alloc/free and new/delete as only one class should own and thus control the lifetime of a disposable instance.
All pure conjecture of course but that's how I'd read it.
MemoryStream wraps a managed buffer that will be garbage collected at some point in the future regardless of whether its disposed of.
The IDisposable implementation is part of the Stream contract. It closes the stream preventing you from using the Read and Write methods but you are still permitted to access the underlying bytes. (Preventing calls to ToArray would probably make it difficult to use with StreamWriters.) A Stream implementation that does use unmanaged resources like a FileStream would release the file handle when it is disposed of.
The code analysis is noting that both you and the StreamWriter are calling Dispose on the same object and warning about it. This is pretty meaningless for a MemoryStream but might be dangerous with some other IDisposable implementations.
You appear to be confusing the IDisposable interface with garbage collection. Calling Dispose does not release managed objects, it just gives your class the opportunity to release unmanaged resources in a deterministic manner.
I think BinaryWriter.Dispose() will call its underlying MemoryStream's .Dispose(), and then your using will re-dispose it.
At least I think that's what will happen. I haven't opened the source for BinaryWriter to verify, but I was always under the impression it closed and disposed its underlying stream.
Edit:
This is the source for the classes. You can see where your memory stream is being disposed:
BinaryStream:
public BinaryWriter(Stream output) : this(output, new UTF8Encoding(false, true))
{
}
public BinaryWriter(Stream output, Encoding encoding)
{
if (output==null)
throw new ArgumentNullException("output");
if (encoding==null)
throw new ArgumentNullException("encoding");
if (!output.CanWrite)
throw new ArgumentException(Environment.GetResourceString("Argument_StreamNotWritable"));
Contract.EndContractBlock();
OutStream = output;
_buffer = new byte[16];
_encoding = encoding;
_encoder = _encoding.GetEncoder();
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
OutStream.Close();
}
MemoryStream:
public class MemoryStream : Stream
{
....
}
Stream
public virtual void Close()
{
Dispose(true);
GC.SuppressFinalize(this);
}
To answer one of your further questions, "why can you still call .ToArray() if MemoryStream has been disposed", well, this test passes just fine:
[TestMethod]
public void TestDispose()
{
var m = new MemoryStream();
m.WriteByte(120);
m.Dispose();
var a = m.ToArray();
Assert.AreEqual(1, a.Length);
}
So the .ToArray() method is still accessible after dispose.
The bytes are still available. MemoryStream dispose just sets some flags internally that prevent you from further modifying the stream:
protected override void Dispose(bool disposing)
{
try {
if (disposing) {
_isOpen = false;
_writable = false;
_expandable = false;
// Don't set buffer to null - allow GetBuffer & ToArray to work.
}
}
finally {
// Call base.Close() to cleanup async IO resources
base.Dispose(disposing);
}
}
In fact, note that the source has the comment in it:
// Don't set buffer to null - allow GetBuffer & ToArray to work.
so that really answers that question :)

Can you keep a StreamReader from disposing the underlying stream?

Is there a way to do this:
this.logFile = File.Open("what_r_u_doing.log", FileMode.OpenOrCreate, FileAccess.ReadWrite);
using(var sr = new StreamReader(this.logFile))
{
// Read the data in
}
// ... later on in the class ...
this.logFile = File.Open("what_r_u_doing.log", FileMode.OpenOrCreate, FileAccess.ReadWrite);
using(var sw = new StreamWriter(this.logFile))
{
// Write additional data out...
}
Without having to open the file twice?
I can't seem to make the StreamReader not-dispose my stream. I don't want to just let it go out of scope, either. Then the garbage collector will eventually call the Dispose, killing the stream.
.NET 4.5 will finally fix this problem with a new constructors on StreamReader and StreamWriter that take a leaveOpen parameter:
StreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize, bool leaveOpen)
StreamWriter(Stream stream, System.Text.Encoding encoding, int bufferSize, bool leaveOpen)
I don't want to just let it go out of scope, either. Then the garbage collector will eventually call the Dispose, killing the stream.
Garbage collector will call the Finalize method (destructor), not the Dispose method. The finalizer will call Dispose(false) which will not dispose the underlying stream. You should be OK by leaving the StreamReader go out of scope if you need to use the underlying stream directly. Just make sure you dispose the underlying stream manually when it's appropriate.
You could use the NonClosingStreamWrapper class from Jon Skeet's MiscUtil library, it serves exactly that purpose
You could create a new class which inherits from StreamReader and override the Close method; inside your Close method, call Dispose(false), which as Mehrdad pointed out, does not close the stream. Same applies to StreamWriter, of course.
However, it seems like a better solution would simply be to hold onto the StreamReader and StreamWriter instances as long as you may need them. If you're already planning to keep the stream open, you might as well keep a StreamReader and StreamWriter open also. If you use StreamWriter.Flush and Stream.Seek correctly, you should be able to make this work even when doing both reading and writing.
Just remove the using-Block. You don't have to Dispose() the StreamReader if you don't want to do Dispose() the stream, I think.
Use another constructor overload where you can specifu a "leaveOpen" parameter to "true"
I always use something like this:
(it also uses the leaveOpen argument)
public static class StreamreaderExtensions
{
public static StreamReader WrapInNonClosingStreamReader(this Stream file) => new StreamReader(file, Encoding.UTF8, true, 1024, true);
}
Usage:
using (var reader = file.WrapInNonClosingStreamReader())
{
....
}
I was able to use leaveOpen parameter without specifying all the constructor params (encoding or buffer size) like this:
using var streaReader = new StreamReader(stream, leaveOpen: true);
Close it yourself in a try/finally clause when you're done with it.
var sr = new StreamReader();
try {
//...code that uses sr
//....etc
}
finally
{
sr.Close();
}

Categories