2010-07-14 5 views
90

He el siguiente código¿Qué sucede si regreso antes del final de la instrucción de uso? ¿Se llamará a los descartados?

using(MemoryStream ms = new MemoryStream()) 
{ 
    //code 
    return 0; 
} 

El método dispose() se llama al final de using declaración de los apoyos } ¿verdad? Desde I return antes del final de la declaración using, ¿se eliminará correctamente el objeto MemoryStream? ¿Qué pasa aquí?

+4

@JonH: Encuentra el duplicado exacto, luego vote para cerrar en ese caso por favor. – Noldorin

+0

@Noldorin: Fui en busca de un engañado en esto, porque pensé que * debe * haberse preguntado antes, pero no pude encontrar uno. Supongo que todavía hay preguntas fáciles por ahí. :) – Randolpho

+0

@JonH y @Noldorin - los duplicados se habrían presentado cuando se formó la pregunta, busca "preguntas similares", una característica que la gente parece no utilizar lo suficiente. –

Respuesta

137

Sí, se llamará Dispose. Se invoca tan pronto como la ejecución abandona el alcance del bloque using, independientemente de los medios necesarios para abandonar el bloque, ya sea al final de la ejecución del bloque, una instrucción return o una excepción.

Como @Noldorin señala correctamente, utilizando un bloque using de código se compila en try/finally, con Dispose ser llamado en el bloque finally. Por ejemplo, el siguiente código:

using(MemoryStream ms = new MemoryStream()) 
{ 
    //code 
    return 0; 
} 

se convierte efectivamente en:

MemoryStream ms = new MemoryStream(); 
try 
{ 
    // code 
    return 0; 
} 
finally 
{ 
    ms.Dispose(); 
} 

Así, pues finally está garantizado para ejecutar después de que el bloque de try ha terminado la ejecución, independientemente de su ruta de ejecución, Dispose se garantiza que sea llamado, no importa qué.

Para obtener más información, vea this MSDN article.

Adición:
Sólo una pequeña advertencia para añadir: Dispose porque se garantiza que sea llamado, es casi siempre una buena idea para asegurarse de que Dispose nunca se produce una excepción cuando se implementa IDisposable. Desafortunadamente, hay algunas clases en la biblioteca central que hacen en ciertas circunstancias cuando se llama al Dispose - ¡Te estoy mirando, WCF Service Reference/Client Proxy! - y cuando eso sucede, puede ser muy difícil rastrear la excepción original si se llamó al Dispose durante un desenrollado de la pila de excepciones, ya que la excepción original se traga a favor de la nueva excepción generada por la llamada Dispose. Puede ser enloquecedoramente frustrante. ¿O eso es frustrantemente enloquecedor? Uno de los dos. Tal vez ambos.

+4

Creo que encontrará que se compila eficazmente en un bloque try-finally con una llamada a 'Dispose' finalmente, por lo que está trabajando efectivamente en la implementación de' finally', como usted describe. – Noldorin

+0

@Noldorin: exactamente. Aunque supongo que podría ser explícito al respecto. Edita próximamente .... – Randolpho

+0

Respuesta simple y efectiva, obtuve mi voto. :) – Noldorin

4

Su objeto MemoryStream se eliminará correctamente, sin necesidad de preocuparse por eso.

0

Tome un vistazo a su código en el reflector tras compilarla. Descubrirá que el compilador refactoriza el código para asegurarse de que se invoque el desecho en la transmisión.

14

using sentencias se comportan exactamente como try ... finally bloques, por lo que siempre se ejecutará en cualquier ruta de acceso de código. Sin embargo, creo que están sujetos a las muy pocas y raras situaciones en las que no se llaman los bloques finally. Un ejemplo que puedo recordar es si el hilo de primer plano sale mientras los hilos de fondo están activos: todos los hilos aparte del GC están en pausa, lo que significa que no se ejecutan los bloques finally.

Obvious edit: se comportan igual de separados de la lógica que les permite manejar objetos IDisposable, d'oh.

Bono contenido: que se pueden apilar (donde se diferencian los tipos):

using (SqlConnection conn = new SqlConnection("string")) 
using (SqlCommand comm = new SqlCommand("", conn)) 
{ 

} 

Y también delimitado por comas (donde los tipos son los mismos):

using (SqlCommand comm = new SqlCommand("", conn), 
     SqlCommand comm2 = new SqlCommand("", conn)) 
{ 

} 
Cuestiones relacionadas