2010-01-30 15 views
11

Oggi ho una domanda riguardante la classe StreamReader. Specificamente inizializzazione questa classe utilizzando il parametro filename per esempio:C# StreamReader in una prova/finalmente

TextReader tr = new StreamReader(fileName); 

Ovviamente quando questa azione è terminata, il suo importante chiudere il flusso così:

tr.Close(); 

Vorrei avere questo in una prova/infine, il problema è che non riesco a trovare un modo per farlo. Qui ci sono alcune varianti che ho trovato che non funzionano:

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

e peggio:

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

Così è possibile avere uno StreamReader stretta in un fine?

+0

Dichiarando TextReader tr; quindi è disponibile alla fine non è un problema. Ma usare è una risposta migliore. – Paparazzi

risposta

23

Il modo più semplice è quello di utilizzare un using dichiarazione:

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

Il compilatore genererà un try-finally per voi e inserire il codice per chiamare Chiudi (in realtà Smaltire) infine.

Se è necessario precisare la finally in modo esplicito, il tuo secondo esempio funzionerà, se non che è necessario forzare tr essere inizializzato:

TextReader tr = null; 

E sarà ovviamente vuole verificare la presenza di tr != null all'interno della vostra infine blocca, nel caso si verifichi un'eccezione prima che sia stato eseguito tr = new StreamReader(...).

+0

Dernit. Batti il ​​messaggio :) –

+1

Quindi questo significa che il metodo close non ha bisogno di essere chiamato manualmente? –

+0

Dannazione, bastonatemi pure ... – t0mm13b

2

Non utilizzare try/finally qui, utilizzare l'istruzione Using, che fa la stessa cosa di quello che si sta facendo con una sintassi più pulita. La risposta è "sì", btw :)

2

si dovrebbe usare la parola chiave using.

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

il metodo Dispose() verrà chiamata con l'oggetto esula dall'ambito alla fine del blocco.

8

Sì, uno:

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 semplicemente:

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

La ragione per il primo pezzo di codice nella tua domanda non ha la compilazione è stata che la variabile tr è stata dichiarata all'interno del try-block , che lo ha reso inaccessibile al blocco finale.

Il motivo per cui il secondo pezzo di codice nella tua domanda non è stato compilato era che alla variabile tr non è stato assegnato un valore, e se lo new XmlSerializer dovesse lanciare un'eccezione, non ne otterrebbe uno nel blocco try , il che significa che hai un possibile valore non definito nella variabile quando raggiunge il blocco finally.

La soluzione, se si desidera assolutamente mantenere una struttura try/finally, è assicurarsi che la variabile abbia un valore iniziale e chiamare solo .Close se è stata modificata.

Naturalmente, il modo più corretto è utilizzare un blocco using, che si prende cura di tutti i dettagli per voi. Nota che questo cambierà l'ordine di costruzione tra il lettore e l'oggetto serializzatore, oppure puoi avere il codice come questo, che conserva l'ordine che hai nella tua domanda (non importa in questo caso però):

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

un commento su questo codice

 
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(); 
     } 

Cosa succede se StreamReader fallisce, allora il blocco finally viene eseguito, ora, qui, tr è ancora null a seguito del fallimento, si finisce con un eccezione all'interno del blocco finally!

E 'preferibile prendere la System.IO.IOException in modo che vi sarà gestire la situazione correttamente invece di mascherare il problema con la gestione di input/output di file ...

Problemi correlati