.netunit-testingdisposabledispose

.NET - Why is disposing of standard output only allowed during unit tests?


First of all, I want to point out that I do not really want to dispose of the standard output...I just want to know why I'm seeing the described behavior. I didn't write the bad code described.

I'm using .NET 4 for the unit tests and .NET 3.5 for the code being tested. I'm using MSTest for .NET 4 as my testing framework.

Recently I have been working with a library that was throwing errors due to the blunder of disposing of the standard error output. (See LibTiff.NET ReadDirectory is giving System.ObjectDisposedException Only During Unit Tests).

This is relatively what their code looked like:

using (TextWriter stderr = Console.Error)
{
    ...
}

Basically, when not running unit tests, the standard output is not disposed even if one specifically disposes of it, but when running unit tests, it is allowed.

Can anyone explain why the standard output is disposable only when doing so in the context of unit tests?


Solution

  • Calling a method on a disposed object will throw ObjectDisposedException. E.g.:

    var textWriter = Console.Error;
    textWriter.Dispose();
    textWriter.WriteLine("Test");
    

    The last line should throw an exception. Except it doesn't always to that.

    If you peruse the BCL source code you can see that Console either uses a StreamWriter (really a synchronized stream writer) that is hooked up to either a "real" stream (e.g. the console error stream) or if that is not available to StreamWriter.Null.

    The "real" StreamWriter is constructed in a special way so that it is not closeable. This means that even if you close it (or dispose it) it just continues to function as expected.

    So if you have a "real" console stream you can close Console.Error as many times as you want without closing the underlying stream. Also you wont get any ObjectDisposedException.

    If there is no "real" stream attached to Console.Error closing the StreamWriter will close the underlying stream (in this case Stream.Null) which doesn't exhibit the special non-closeable behavior, and if you try to use the StreamWriter later you will get an ObjectDisposedException.

    The bottom line is that you can get a ObjectDisposedException if you close a console stream writer prematurely in an application that doesn't have a real console stream.

    The information above also applies to Console.Out.