Clases, tales como Stream
, StreamReader
, StreamWriter
etc. implementos IDisposable
interfaz. Eso significa que podemos llamar al Dispose()
método en objetos de estas clases. También han definido un public
método llamado Close()
. Ahora eso me confunde, ¿qué debo llamar una vez que haya terminado 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 puede ver, he escrito using()
construcciones, que llaman automáticamente al Dispose()
método en cada objeto. Pero también llamo Close()
métodos. ¿Es correcto?
Sugiérame las mejores prácticas al usar objetos de flujo. :-)
El ejemplo de MSDN no utiliza using()
construcciones y Close()
método de llamada :
¿Esta bien?
using (MemoryStream ms1 = new MemoryStream(), ms2 = new MemoryStream()) { }
. Me refiero a esto donde puedes redefinir el tipo:using (MemoryStream ms = new MemoryStream()) using (FileStream fs = File.OpenRead("c:\\file.txt")) { }
Respuestas:
Un salto rápido a Reflector.NET muestra que el
Close()
métodoStreamWriter
es:Y
StreamReader
es:La
Dispose(bool disposing)
anulación enStreamReader
es:El
StreamWriter
método es similar.Entonces, al leer el código, está claro que puede llamar
Close()
yDispose()
transmitir en línea con la frecuencia que desee y en cualquier orden. No cambiará el comportamiento de ninguna manera.Por lo tanto, se trata de si es o no más legible de usar
Dispose()
,Close()
y / ousing ( ... ) { ... }
.Mi preferencia personal es que
using ( ... ) { ... }
siempre debe usarse cuando sea posible, ya que le ayuda a "no correr con unas tijeras".Pero, si bien esto ayuda a la corrección, reduce la legibilidad. En C # ya tenemos una gran cantidad de llaves cerradas, ¿cómo sabemos cuál realmente realiza el cierre en la secuencia?
Así que creo que es mejor hacer esto:
No afecta el comportamiento del código, pero ayuda a la legibilidad.
fuente
Close()
llamada redundante . Si alguien con menos experiencia mira el código y no lo sabe,using
él: 1) lo buscará y aprenderá , o 2) agregará ciegamente unClose()
manual. Si elige 2), tal vez algún otro desarrollador verá el redundanteClose()
y, en lugar de "reírse", instruya al desarrollador menos experimentado. No estoy a favor de hacerles la vida difícil a los desarrolladores sin experiencia, pero estoy a favor de convertirlos en desarrolladores experimentados.No, no debe llamar a esos métodos manualmente. Al final del
using
bloqueDispose()
, se llama automáticamente al método que se encargará de liberar recursos no administrados (al menos para las clases estándar de .NET BCL, como secuencias, lectores / escritores, ...). Entonces también podría escribir su código de esta manera:El
Close()
método llamaDispose()
.fuente
using
el primero,responseStream
ya que está envuelto por elreader
que se asegurará de que esté cerrado cuando el lector esté dispuesto. +1 no obstanteThe Close method calls Dispose.
... y en el resto de tu publicación, estás insinuando queDispose()
llamaríaClose()
, no debería llamar a esta última manualmente. ¿Estás diciendo que se llaman?using
bloque. Estoy implementando una clase que escribe de vez en cuando y, por lo tanto, no puedo.using
(o, nuevamente, ir al Dispose Pattern).La documentación dice que estos dos métodos son equivalentes:
Entonces, ambos son igualmente válidos:
Personalmente, me quedaría con la primera opción, ya que contiene menos "ruido".
fuente
En muchas clases que admiten ambos
Close()
yDispose()
métodos, las dos llamadas serían equivalentes. En algunas clases, sin embargo, es posible volver a abrir un objeto que se ha cerrado. Algunas de esas clases pueden mantener vivos algunos recursos después de un Cierre, para permitir la reapertura; otros pueden no mantener ningún recurso vivoClose()
, pero pueden establecer una banderaDispose()
para prohibir explícitamente la reapertura.El contrato
IDisposable.Dispose
requiere explícitamente que llamarlo a un objeto que nunca se volverá a usar será inofensivo, por lo que recomendaría llamar a unoIDisposable.Dispose
o a un método llamadoDispose()
a cadaIDisposable
objeto, ya sea que uno también llame o noClose()
.fuente
Esta es una pregunta antigua, pero ahora puede escribir usando declaraciones sin necesidad de bloquear cada una. Se eliminarán en orden inverso cuando finalice el bloque contenedor.
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/using
fuente