Does .Disposing a StreamWriter close the underlying stream?

前端 未结 6 2003
星月不相逢
星月不相逢 2020-12-01 18:02

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 underlyi

相关标签:
6条回答
  • 2020-12-01 18:08

    Close and Dispose are synonymous for StreamWriter.

    0 讨论(0)
  • 2020-12-01 18:09

    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.

    0 讨论(0)
  • 2020-12-01 18:12

    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 :)

    0 讨论(0)
  • 2020-12-01 18:12

    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.

    0 讨论(0)
  • 2020-12-01 18:15

    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.

    0 讨论(0)
  • 2020-12-01 18:28

    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.

    0 讨论(0)
提交回复
热议问题