c# .net

c# - ¿.Disponiendo un StreamWriter cierra la secuencia subyacente?



.net (6)

El StreamWriter.Close () dice que también cierra la secuencia subyacente de StreamWriter. ¿Qué pasa con StreamWriter.Dispose? Does Dispose también elimina y / o cierra el flujo subyacente


Algunas personas dirán, simplemente no desechen la transmisión, esta es una muy mala idea, porque una vez que el generador de secuencias sale del alcance, GarbageCollection puede recogerlo en cualquier momento y colocarlo, cerrando así el Handle a la secuencia, pero creando una clase descendiente que anula este comportamiento de StreamWriter es fácil, aquí está el código:

/// <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); } }

Si miras en Reflector / ILSpy, encontrarás que el cierre de la transmisión base se realiza en Dispose (verdadero), y cuando se llama close, solo llama a Dispose which calls Dispose (True), del código no debería haber otro efectos secundarios, por lo que la clase anterior funciona bien.

Es posible que desee agregar todos los constructores, acabo de agregar 2 aquí por simplicidad.


Close y Dispose también son para StreamWriter.


Desde StreamWriter.Close ()

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

From TextWriter.Dispose () (que StreamWriter hereda)

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

Ellos son así, idénticos.


La respuesta es simple, y se proporciona arriba: sí, la eliminación de una secuencia cierra cualquier flujo subyacente. Aquí hay un ejemplo:

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; }

y aquí está la solución, donde tienes que retrasar el Dispose donde ya no se necesita el MemoryStream subyacente:

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; }

Al mirar estos ejemplos, no entiendo por qué cerrar el flujo subyacente es una característica.

Solo me gusta compartir esto.


Para citar las Pautas de diseño del marco por Cwalina y Abrams en la sección sobre el patrón de disposición:

CONSIDERAR que proporciona el método Close() , además de Dispose() , si close es la terminología estándar en el área.

Al parecer, Microsoft sigue sus propias pautas y supone que esto es casi siempre una apuesta segura para la biblioteca de clases base de .NET.


StreamWriter.Close () solo llama a StreamWriter.Dispose () debajo del capó, por lo que hacen exactamente lo mismo. StreamWriter.Dispose () cierra la secuencia subyacente.

Reflector es tu amigo para preguntas como esta :)