sirve recursos que para operando objeto net miembro memoria liberar interfaz implementar implementa debe administrados c# stream idisposable streamreader streamwriter

c# - recursos - ¿Debo llamar a Close() o Dispose() para los objetos de transmisión?



recursos no administrados (4)

Las clases como Stream , StreamReader , StreamWriter , etc. implementan IDisposable interfaz IDisposable . Eso significa que podemos llamar al método Dispose() en los objetos de estas clases. También definieron un método public llamado Close() . Ahora que me confunde, ¿a qué debo llamar una vez que termine con los objetos? ¿Qué pasa si llamo a ambos?

Mi código actual es este:

using (Stream responseStream = response.GetResponseStream()) { using (StreamReader reader = new StreamReader(responseStream)) { using (StreamWriter writer = new StreamWriter(filename)) { int chunkSize = 1024; while (!reader.EndOfStream) { char[] buffer = new char[chunkSize]; int count = reader.Read(buffer, 0, chunkSize); if (count != 0) { writer.Write(buffer, 0, count); } } writer.Close(); } reader.Close(); } }

Como ve, escribí constructos using() , que llaman automáticamente al método Dispose() en cada objeto. Pero también llamo a métodos Close() . ¿Es correcto?

Por favor, sugiera las mejores prácticas al usar objetos de transmisión. :-)

El ejemplo de MSDN no usa construcciones using() y llama al método Close() :

¿Esta bien?


En muchas clases que admiten métodos Close y Dispose, las dos llamadas serían equivalentes. En algunas clases, sin embargo, es posible volver a abrir un objeto que ha sido Close''d. Algunas de estas clases pueden mantener vivos algunos recursos después de un Cierre, para permitir la reapertura; otros pueden no mantener recursos vivos en Cerrar, pero pueden establecer un indicador en Eliminar para prohibir explícitamente la reapertura.

El contrato para IDisposable.Dispose requiere explícitamente que llamarlo a un objeto que nunca se volverá a utilizar será, en el peor de los casos, inofensivo, por lo que recomendaría llamar IDisposable.Dispose o un método llamado Dispose en cada objeto IDisposable, ya sea que llama Cerrar.


La documentación dice que estos dos métodos son equivalentes:

StreamReader.Close : esta implementación de Close llama al método Dispose que pasa un valor verdadero.

StreamWriter.Close : esta implementación de Close llama al método Dispose que pasa un valor verdadero.

Stream.Close : este método llama a Dispose, especificando true para liberar todos los recursos.

Entonces, ambos son igualmente válidos:

/* Option 1 */ using (StreamWriter writer = new StreamWriter(filename)) { // do something } /* Option 2 */ StreamWriter writer = new StreamWriter(filename) try { // do something } finally { writer.Close(); }

Personalmente, me quedaría con la primera opción, ya que contiene menos "ruido".


No, no deberías llamar esos métodos manualmente. Al final del bloque de using , se llama automáticamente al método Dispose, que se ocupará de liberar recursos no administrados (al menos para las clases .NET BCL estándar tales como secuencias, lectores / escritores, ...). Entonces también puedes escribir tu código así:

using (Stream responseStream = response.GetResponseStream()) using (StreamReader reader = new StreamReader(responseStream)) using (StreamWriter writer = new StreamWriter(filename)) { int chunkSize = 1024; while (!reader.EndOfStream) { char[] buffer = new char[chunkSize]; int count = reader.Read(buffer, 0, chunkSize); if (count != 0) { writer.Write(buffer, 0, count); } } }

El método Close llama a Dispose.


Un salto rápido a Reflector.NET muestra que el método Close() en StreamWriter es:

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

Y StreamReader es:

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

La anulación de Dispose(bool disposing) en StreamReader es:

protected override void Dispose(bool disposing) { try { if ((this.Closable && disposing) && (this.stream != null)) { this.stream.Close(); } } finally { if (this.Closable && (this.stream != null)) { this.stream = null; /* deleted for brevity */ base.Dispose(disposing); } } }

El método StreamWriter es similar.

Entonces, al leer el código, está claro que puede llamar a Close() y a Dispose() en las transmisiones con la frecuencia que desee y en cualquier orden. No cambiará el comportamiento de ninguna manera.

De modo que todo se reduce a si es o no más fácil usar Dispose() , Close() y / o using ( ... ) { ... } .

Mi preferencia personal es que using ( ... ) { ... } siempre que sea posible, ya que le ayuda a "no usar tijeras".

Pero, aunque esto ayuda a la corrección, sí reduce la legibilidad. En C #, ya tenemos una plétora de llaves de cierre, entonces, ¿cómo sabemos cuál de las dos realiza el cierre en la transmisión?

Entonces creo que es mejor hacer esto:

using (var stream = ...) { /* code */ stream.Close(); }

No afecta el comportamiento del código, pero ayuda a la legibilidad.