3

I have the following code. In here I am using the StreamReader constructor with leaveOpen: true and in order to do that I need to give the previous parameters which I manage to get their default values. This is cumbersome. Since I use stream with using do I gain anything for using the StreamReader with using? Does answer change if it is a StreamWriter instead?

using (Strem stream = ...)
{
    ...
    using (StreamReader sr = new StreamReader(stream, Encoding.UTF8, true, 1024, true))
    {
        ...
    }
    ...
}

What if any do I lose if use the following code instead?

using (Strem stream = ...)
{
    ...
    StreamReader sr = new StreamReader(stream);

    ...

    ...
}
Community
  • 1
  • 1
Nuri Tasdemir
  • 9,720
  • 3
  • 42
  • 67

2 Answers2

4

You do need to close a StreamWriter (generally via the using block), or else data in its buffer could be lost.

Because both StreamReader and StreamWriter default to closing the stream automatically, if you want to eliminate one using block from your code, it should be the Stream that you remove from using.

If you can't do that, for example you've borrowed the Stream from elsewhere that doesn't want you to close it, then you must use the leaveOpen parameter you're already aware of. The reason that you can't just omit the using statement for a StreamReader/StreamWriter in order to leave it open, is that the garbage collector will still trigger some cleanup (although not as much) since the object is unreachable... only this will now occur at an unrelated time, creating an unpredictable bug that's very hard to find.

It is indeed ugly that you can't specify leaveOpen without explicitly controlling the buffer size, etc. May I suggest a helper method along the lines of StreamReader CreateStreamReaderLeaveOpen(Stream)?

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
3

Because you have leaveOpen set to true in the constructor disposing of a StreamReader does nothing execpt call the the Dispose method of the TextReader class, which itself does nothing at all.

protected override void Dispose(bool disposing)
{
    // Dispose of our resources if this StreamReader is closable.
    // Note that Console.In should be left open.
    try {
        // Note that Stream.Close() can potentially throw here. So we need to 
        // ensure cleaning up internal resources, inside the finally block.  
        if (!LeaveOpen && disposing && (stream != null))
            stream.Close();
    }
    finally {
        if (!LeaveOpen && (stream != null)) {
            stream = null;
            encoding = null;
            decoder = null;
            byteBuffer = null;
            charBuffer = null;
            charPos = 0;
            charLen = 0;
            base.Dispose(disposing);
        }
    }
}

With a StreamWriter it does change a bit because it will not flush it's internal buffers to the underlying stream unless you dispose of the writer.

Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431
  • The question asked about `StreamWriter` as well, which has much more complex conditions for performing operations (including Flush on the stream) at the time of `Dispose()`. – Ben Voigt May 08 '17 at 14:09
  • Is there a benefit to using LeaveOpen? I saw some example code set this bit true inside a while loop created streamReader. – dellos Jun 09 '22 at 01:39