Sep 30, 2011

When Dispose Throws the Baby Out with the Bathwater

As I said in my last post, there is a lot to like about .NET but every now and then they do some really screwy stuff. This post is about BinaryReader and BinaryWriter and why you shouldn't dispose of the them when you're done with them (or do the equivalent by  putting them in using statements), unless you follow one particular idiom of usage. That idiom is the one you see in MSDN and in a lot of examples. Unfortunately, nothing I've seen in MSDN (or in my Nutshell reference) properly explains what is going on here.

The idiom typically wraps the creation of the stream inside the creation of the BinaryWriter e.g.

  1. using (BinaryWriter binWriter =
  2.  new BinaryWriter(File.Open(filename, FileMode.Create)))
  3. {
  4. }

The enclosed call to File.Open returns a FileStream. A FileStream derives from Stream and all Stream's are disposable.  Who owns it? Who should dispose of it? Looking at this example it seems obvious that BinaryWriter is the only one that can dispose of it. But what happens when you don't use this idiom? For example, assume you have a previously created Stream you're going to use for an extended period of time. Say you open a TCP connection with TcpListener and get the underlying stream:

  1. _serverTcpClient = _tcpServer.AcceptTcpClient();
  2. _myClientStream = _serverTcpClient.GetStream();

Mostly you're going to use this stream directly via something like _myClientStream.Write(data, offset, size). But maybe there's a point where a BinaryWriter can help you; say you want to kick start communications with a protocol message:

  1. BinaryWriter w = new BinaryWriter(_myClientStream);
  2. w.Write("Hello");
  3. w.Flush();

If you strive to be careful about disposing of everything that should be disposed you probably think it would be better to write

Code Snippet
  1. using (BinaryWriter w = new BinaryWriter(_myClientStream))
  2. {
  3.     w.Write("Hello");  
  4. }

Or at least to manually call w.Dispose(), but you'd only be right, if sending "Hello" is the last  thing you ever want to do with _myClientStream. This is counterintuitive to me, the stream was created in another method in this class and lives in a member field, it seems obvious that BinaryWriter doesn't own this resource and shouldn't dispose of it when finished. The reason it behaves this way is because of the previous idiom where the stream is created in the constructor of BinaryWriter. This tells me this idiom is wrong and shouldn't be used but .NET decided (wrongly) that this was the only useful idiom that would ever be used so they dispose of the stream. It's just one of those little gotcha's you need to be aware of. Just keep the bathwater (the dog will drink it any way), it's better than throwing out the baby.

Readers' Most Popular Posts