2010-10-19 7 views
6

Si usted vino a través de un código C# como este con anidadas utilizando declaraciones/recursos:.NET - Sustitución anidada utilizando declaraciones con una sola instrucción using

using (var response = (HttpWebResponse)request.GetResponse()) 
{ 
    using (var responseStream = response.GetResponseStream()) 
    { 
     using (var reader = new BinaryReader(responseStream)) 
     { 
      // do something with reader 
     } 
    } 
} 

¿Es seguro para reemplazarlo con algo como esto?

using (var reader = new BinaryReader(((HttpWebResponse)request.GetResponse()).GetResponseStream())) 
{ 
    // do something with reader 
} 

El ejemplo anterior es sólo un ejemplo de los recursos anidados desechables, así que perdónenme si no es exactamente correcto uso. Tengo curiosidad por saber cuándo desechar el recurso más externo (el BinaryReader en este caso), si se deshace recursivamente de sus hijos, o si necesita disponer explícitamente de cada "capa" con instrucciones de uso separadas. P.ej. si dispone del BinaryReader, ¿se supone que debe eliminar el flujo de respuesta, que a su vez elimina la respuesta? Pensando en la última oración me hace pensar que en realidad necesitas las instrucciones de uso separadas, porque no hay forma de garantizar que un objeto envoltorio elimine el objeto interno. ¿Está bien?

Respuesta

12

Necesita las instrucciones de uso separadas.

En su segundo ejemplo, solo el BinaryReader será eliminado, no los objetos utilizados para construirlo.

Para ver por qué, mire lo que realmente hace el using statement. Toma su segundo código, y hace algo equivalente a:

{ 
    var reader = new BinaryReader(((HttpWebResponse)request.GetResponse()).GetResponseStream()); 
    try 
    { 
     // do something with reader 
    } 
    finally 
    { 
     if (reader != null) 
      ((IDisposable)reader).Dispose(); 
    } 
} 

Como se puede ver, no habría nunca una llamada Dispose() en el Response o ResponseStream.

+0

Las necesita, pero no creo que necesiten anidarse. Creo que pueden apilarse uno encima del otro. –

+0

@Matt: Sí, pero deben existir los tres. –

+0

'BinaryReader.Close' cierra la secuencia subyacente. Y como 'Stream.Close' termina llamando' Stream.Dispose', no hay necesidad de cerrar la secuencia después de cerrar el lector. Consulte http://msdn.microsoft.com/en-us/library/system.net.httpwebresponse.aspx y http://msdn.microsoft.com/en-us/library/system.io.stream.close.aspx . –

13

Usted sólo debe apilar utilizando declaraciones - que tiene el efecto deseado que busca:

using (var response = (HttpWebResponse)request.GetResponse()) 
using (var responseStream = response.GetResponseStream()) 
using (var reader = new BinaryReader(responseStream)) 
{ 
    // do something with reader 
} 
+0

Esto es, esencialmente, el mismo código con diferentes formatos (simplemente quitando los frenos). –

+0

Cómo mejora esto, eso es lo que el OP tenía justo menos las llaves que eran opcionales para las dos primeras declaraciones 'using'. – slugster

+0

Sí, es lo mismo, pero en comparación con lo que el autor quería reemplazar con el original, es mucho más fácil de leer y mantener –

3

Fwiw, aquí hay otra manera de deletrear su original ejemplo que puede adaptarse a cualquier consternación por la anidación:

using (var response = (HttpWebResponse)request.GetResponse()) 
using (var responseStream = response.GetResponseStream()) 
using (var reader = new BinaryReader(responseStream)) 
{ 
    // do something with reader 
} 

Si el lector dispone de la secuencia es realmente una función del lector, no el 'uso'. Como recuerdo, ese es el comportamiento habitual de los lectores: se apropian de la transmisión y la eliminan cuando el lector está cerrado. Pero el formulario que proporcioné arriba debería estar bien.

1

De acuerdo con la documentación, BinaryReader.Close cerrará la transmisión subyacente. http://msdn.microsoft.com/en-us/library/system.io.binaryreader.close.aspx

Además, según la documentación para HttpWebResponse, debe cerrar la secuencia subyacente o eliminar la respuesta. http://msdn.microsoft.com/en-us/library/system.net.httpwebresponse.aspx

Así que el segundo ejemplo que proporcionó funcionaría.

+0

Gracias por la respuesta ... Sospeché que había otras posibilidades. Supongo que, en caso de duda, lo mejor es cerrar o desechar todo, a menos que sepa lo que hace cada tipo. –

0

Lo publiqué en otro lugar, pero separar sus declaraciones por coma parece tratar cada declaración separada de esta manera como una nueva declaración y disponer de ellas.

using (IType1 a = new Type1(), b = new Type1()){}

Sin embargo, esto significa que los objetos deben ser del mismo tipo.Se les puede llamar como

using (IDisposable a = new Type1(), b = new Type2()){}

Pero entonces, por supuesto, que sólo tienen acceso a métodos IDisposable, sin poner el objeto, que es un poco tonto. Así que en lugar, creo que se puede utilizar

using (var a = new Type1(), b = new Type2()){}

Esto parece darle las referencias a objetos correctamente escritas que le permite acceder al método apropiado del tipo asignado, y dispone tanto de los objetos creados. Si alguien sabe por qué no estoy en lo correcto, hágamelo saber porque esto parece funcionar para mí. (Sé que esta pregunta es realmente vieja, pero es todo lo que pude encontrar mientras buscaba esta respuesta yo mismo)

Cuestiones relacionadas