nos
nos

Reputation: 229058

Does .Disposing a StreamWriter close the underlying stream?

The StreamWriter.Close() says it also closes the underlying stream of the StreamWriter. What about StreamWriter.Dispose ? Does Dispose also dispose and/or close the underlying stream

Upvotes: 66

Views: 34795

Answers (7)

Rob Levine
Rob Levine

Reputation: 41298

StreamWriter.Close() just calls StreamWriter.Dispose() under the bonnet, so they do exactly the same thing. StreamWriter.Dispose() does close the underlying stream.

Reflector is your friend for questions like this :)

Upvotes: 66

psurikov
psurikov

Reputation: 3458

The Dispose method of StreamWriter also closes the underlying stream. You can check this in the reference source here. One thing that you can do is to use a different constructor, which explicitly tells whether to close or keep the stream open. Check the leaveOpen arg:

public StreamWriter(Stream stream, Encoding encoding, int bufferSize, bool leaveOpen) : base(null)

If you plan to leave it open, then it's a good idea to pass the flag set to 'true', but then dispose the stream writer itself, so it doesn't keep a reference to the stream and potentially could dispose other resources (though it doesn't look like there are any resources besides the stream).

Upvotes: 1

Roland
Roland

Reputation: 5234

The answer is simple, and provided above: yes, disposing a stream closes any underlying stream. Here is an example:

    public static string PrettyPrintXML_bug(XDocument document)
    {
        string Result = "";
        using (MemoryStream mStream = new MemoryStream())
        {
            using (XmlTextWriter writer = new XmlTextWriter(mStream, Encoding.Unicode))
            {
                writer.Formatting = Formatting.Indented; // <<--- this does the trick
                // Write the XML into a formatting XmlTextWriter
                document.WriteTo(writer);
                // change the memory stream from write to read
                writer.Flush();
                mStream.Flush();
            } // <-- <-- <-- <-- <-- <-- <-- <-- <-- <-- this also "closes" mStream
            mStream.Position = 0;//rewind    <-- <-- <-- "cannot Read/Write/Seek"
            // Read MemoryStream contents into a StreamReader.
            using (StreamReader sReader = new StreamReader(mStream)) //  <-- <-- Exception: Cannot access a closed stream
            {
                // Extract the text from the StreamReader.
                Result = sReader.ReadToEnd();
            }
        }
        return Result;
    }

and here the solution, where you have to delay Dispose to where the underlying MemoryStream is not needed anymore:

    public static string PrettyPrintXML(XDocument document)
    {
        string Result = "";
        using (MemoryStream mStream = new MemoryStream())
        {
            using (XmlTextWriter writer = new XmlTextWriter(mStream, Encoding.Unicode))
            {
                writer.Formatting = Formatting.Indented; // <<--- this does the trick
                // Write the XML into a formatting XmlTextWriter
                document.WriteTo(writer);
                // change the memory stream from write to read
                writer.Flush();
                writer.Close();
                mStream.Flush();
                mStream.Position = 0;//rewind
                // Read MemoryStream contents into a StreamReader.
                using (StreamReader sReader = new StreamReader(mStream))
                {
                    // Extract the text from the StreamReader.
                    Result = sReader.ReadToEnd();
                }
            }// <-- here the writer may be Disposed
        }
        return Result;
    }

Looking at these examples, I do not understand why closing the underlying stream is a feature.

I just liked to share this.

Upvotes: 2

Aaron Murgatroyd
Aaron Murgatroyd

Reputation: 1546

Some people will say, just dont dispose the stream, this is a really bad idea, because once the streamwriter goes out of scope GarbageCollection can pick it up anytime and dipose it, thus closing the Handle to the stream, but creating a descendant class which overrides this behaviour of StreamWriter is easy, heres the code:

/// <summary>
/// Encapsulates a stream writer which does not close the underlying stream.
/// </summary>
public class NoCloseStreamWriter : StreamWriter
{
    /// <summary>
    /// Creates a new stream writer object.
    /// </summary>
    /// <param name="stream">The underlying stream to write to.</param>
    /// <param name="encoding">The encoding for the stream.</param>
    public NoCloseStreamWriter(Stream stream, Encoding encoding)
        : base(stream, encoding)
    {
    }

    /// <summary>
    /// Creates a new stream writer object using default encoding.
    /// </summary>
    /// <param name="stream">The underlying stream to write to.</param>
    /// <param name="encoding">The encoding for the stream.</param>
    public NoCloseStreamWriter(Stream stream)
        : base(stream)
    {
    }

    /// <summary>
    /// Disposes of the stream writer.
    /// </summary>
    /// <param name="disposing">True to dispose managed objects.</param>
    protected override void Dispose(bool disposeManaged)
    {
        // Dispose the stream writer but pass false to the dispose
        // method to stop it from closing the underlying stream
        base.Dispose(false);
    }
}

If you look in Reflector / ILSpy you will find that the closing of the base stream is actually done in Dispose(true), and when close is called it just calls Dispose which calls Dispose(True), from the code there should be no other side effects, so the class above works nicely.

You might want to add all the constructors though, i have just added 2 here for simplicity.

Upvotes: 19

Martin Liversage
Martin Liversage

Reputation: 106796

To quote from Framework Design Guidelines by Cwalina and Abrams in the section about the dispose pattern:

CONSIDER providing method Close(), in addition to the Dispose(), if close is standard terminology in the area.

Apparently Microsoft follow their own guidelines, and assuming this is almost always a safe bet for the .NET base class library.

Upvotes: 2

ShuggyCoUk
ShuggyCoUk

Reputation: 36438

From StreamWriter.Close()

public override void Close()
{
    this.Dispose(true);
    GC.SuppressFinalize(this);
}

From TextWriter.Dispose() (which StreamWriter inherits)

public void Dispose()
{
    this.Dispose(true);
    GC.SuppressFinalize(this);
}

They are thus, identical.

Upvotes: 14

Joel Coehoorn
Joel Coehoorn

Reputation: 415600

Close and Dispose are synonymous for StreamWriter.

Upvotes: 6

Related Questions