2010-01-30 9 views
11

Tengo una pregunta hoy que involucra la clase StreamReader. Específicamente inicialización de esta clase mediante el parámetro de nombre de archivo, por ejemplo:C# StreamReader en una prueba/finalmente

TextReader tr = new StreamReader(fileName); 

Obviamente, cuando se termina esta acción, es importante cerrar el flujo de la siguiente manera:

tr.Close(); 

me gustaría tener esto en una oportunidad/finalmente, el problema es que no puedo encontrar una manera de hacer esto. Aquí hay algunas variaciones que he encontrado que no funcionan:

try 
     { 
      var serializer = new XmlSerializer(type); 
      TextReader tr = new StreamReader(fileName); 
      var obj = serializer.Deserialize(tr); 
     } 
    finally 
     { 
      tr.Close();  
     } 

y peor:

 TextReader tr; 
     try 
     { 
      var serializer = new XmlSerializer(type); 
      tr = new StreamReader(fileName); 
      var obj = serializer.Deserialize(tr); 
     } 
     finally 
     { 
      tr.Close();  
     } 

Así es posible tener una estrecha StreamReader en un fin?

+0

Declarar tr TextReader; por lo que está disponible para el finalmente no es un problema. Pero usar es una mejor respuesta. – Paparazzi

Respuesta

23

La forma más sencilla es utilizar una declaración using:

using (TextReader tr = new StreamReader(fileName)) 
{ 
    // ... 
} 

el compilador generará un try-finally para usted y poner el código para llamar Cerrar (en realidad Dispose) en el finalmente.

Si necesita deletrear el finally de forma explícita, el segundo ejemplo funcionará, salvo que se debe a la fuerza tr ser inicializado:

TextReader tr = null; 

Y, por supuesto, que desee comprobar para tr != null dentro de su finalmente bloquear, en caso de que ocurriera una excepción antes de que se haya ejecutado tr = new StreamReader(...).

+0

Dernit. Pásame a la publicación :) –

+1

Entonces, ¿eso significa que el método de cierre, no necesita ser llamado manualmente? –

+0

Maldita sea, pásame también ... – t0mm13b

2

No use try/finally aquí, use la instrucción Using, que hace lo mismo que lo que está haciendo con la sintaxis más limpia. La respuesta es "sí", por cierto :)

2

debe usar la palabra clave using.

using (TextReader tr = new StreamReader(fileName)) 
{ 
    var obj = serializer.Deserialize(tr); 
} 

Se llamará al método Dispose() con el objeto fuera del alcance al final del bloque.

8

Sí, ya sea:

TextReader tr = null; 
try 
{ 
    var serializer = new XmlSerializer(type); 
    tr = new StreamReader(fileName); 
    var obj = serializer.Deserialize(tr); 
} 
finally 
{ 
    if (tr != null) 
     tr.Close();  
} 

o simplemente:

using (TextReader tr = new StreamReader(fileName)) 
{ 
    var serializer = new XmlSerializer(type); 
    var obj = serializer.Deserialize(tr); 
} 

La razón por la primera pieza de código en su pregunta no compilar fue que la variable tr fue declarado dentro del intento de bloque , que lo hizo inaccesible para el bloque final.

La razón por la cual la segunda parte del código en su pregunta no se compiló es que a la variable tr no se le dio un valor, y si el new XmlSerializer lanzara una excepción, tampoco la obtendría en el try-block , lo que significa que tiene un posible valor indefinido en la variable cuando alcanza el bloque final.

La solución, si quiere mantener absolutamente una estructura try/finally, es asegurarse de que la variable tenga un valor inicial, y solo llame al .Close si ha cambiado.

Por supuesto, la forma más correcta es usar un bloque using, que se encarga de todos los detalles por usted. Tenga en cuenta que esto cambiará el orden de construcción entre el lector y el objeto del serializador, o puede tener un código como este, que conserva el orden que tenía en su pregunta (aunque no importará en este caso):

var serializer = new XmlSerializer(type); 
using (TextReader tr = new StreamReader(fileName)) 
{ 
    var obj = serializer.Deserialize(tr); 
} 
3

un comentario para este código

 
TextReader tr; 
     try 
     { 
      var serializer = new XmlSerializer(type); 
      tr = new StreamReader(fileName); 
      var obj = serializer.Deserialize(tr); 
     } 
     finally 
     { 
      //tr.Close(); 
      // Correct way 
      if (tr != null) tr.Close(); 
     } 

¿Qué pasa si StreamReader falla, entonces el bloque finally es ejecutado, ahora, aquí, tr sigue siendo null como resultado de la falla, el resultado final será con una excepción dentro del bloque finally!

Es preferible coger el System.IO.IOException manera que va a manejar la situación adecuadamente en lugar de enmascarar el problema con el manejo de entrada/salida de archivo ...

Cuestiones relacionadas