2011-03-04 12 views
9

¿Podría alguien explicarme por qué el código que se muestra a continuación es válido en C# y ejecuta la llamada al Console.WriteLine?¿Por qué usar (nulo) un caso válido en C#?

using (null) 
{ 
    Console.WriteLine ("something is here") 
} 

Se compila en (finalmente se muestra el bloque). Como puede ver, el compilador decide no ejecutar el método Dispose() y salta a la instrucción endfinally.

IL_0013: ldnull 
IL_0014: ceq 
IL_0016: stloc.1 
IL_0017: ldloc.1 
IL_0018: brtrue.s IL_0021 // branches here and decide not to execute Dispose() 
IL_001a: ldnull 
IL_001b: callvirt instance void [mscorlib]System.IDisposable::Dispose() 
IL_0020: nop 
IL_0021: endfinally 

Sin embargo, si se me acaba el código siguiente, se producirá un error con un NullReferenceException (que se espera):

((IDisposable)null).Dispose(); 
IL_0023: ldnull 
IL_0024: callvirt instance void [mscorlib]System.IDisposable::Dispose() 

Por qué se compila la primera versión? ¿Por qué el compilador decide no ejecutar Dispose()? ¿Hay algún otro caso en el que el compilador decida no llamar al Dispose() en un bloque using?

+7

hmmm ... Ahora estoy muy dudosa de este post, dada reciente blog de Eric ... ¿es realmente una pregunta genuina? –

+0

¿No es esto ya preguntado? http://stackoverflow.com/questions/2522822/c-using-statement-with-a-null-object –

+0

Sí, parecía artificial para mí. –

Respuesta

11

La especificación idioma afirma explícitamente (8,13) que el valor capturado se prueba para nulo si es necesario, es decir, el finally es esencialmente (con salvedades alrededor de tipos no anulable)

if(tmp != null) tmp.Dispose(); 

frecuencia Lo utilizo para mi ventaja, para cosas que podría ser nulo, pero cuando no lo son: necesita deshacerse. De hecho, aquí hay un escenario útil (enumerar manualmente IEnumerable):

IEnumerable blah = ...; // note non-generic version 
IEnumerator iter = blah.GetEnumerator(); 
using(iter as IDisposable) 
{ 
    // loop 
} 

como la versión no genérica de IEnumerator no es necesariamente IDisposable, pero cuando lo es, debe desecharse.

+0

Gracias por un buen truco con * como IDisposable *. Exactamente lo que estaba buscando. –

+0

Eso es inteligente, me gusta. – Travis

+0

Esto es demasiado inteligente para mi gusto :) – mafu

1

Creo que es un resultado natural del caso más general de using(some_expression), donde some_expressionis allowed to evaluate to null.

Habría requerido una regla especial para distinguir este caso del más general.

0
+0

¿Dónde dice eso en la documentación que vinculó? Una búsqueda de 'null' en esa página arrojó 0 aciertos. –

+0

En la sección de comentarios. if (font1! = null) ((IDisposable) font1) .Dispose(); – Anuraj

+0

> Una sentencia using se traduce en tres partes: adquisición, uso y eliminación. El uso del recurso se incluye implícitamente en una instrucción try que incluye una cláusula finally. Esta cláusula final dispone del recurso. Si se adquiere un recurso nulo, no se realiza ninguna llamada a Dispose y no se lanza ninguna excepción. https://msdn.microsoft.com/en-us/library/aa664736(v=vs.71).aspx – boro

Cuestiones relacionadas