2010-10-19 16 views
6

Se vi siete imbattuti in qualche codice C# come questo con nidificati che utilizzano le dichiarazioni/risorse:.NET - Sostituzione annidati usando affermazioni con un'unica istruzione using

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

E 'sicuro di sostituirlo con qualcosa di simile?

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

L'esempio sopra è solo un esempio delle risorse disponibili nidificati, così mi perdoni se non è esattamente corretto utilizzo. Sono curioso di sapere se quando smaltisci la risorsa più esterna (il BinaryReader in questo caso), se distribuirà ricorsivamente i suoi figli per te, o se hai bisogno di disporre esplicitamente di ogni "layer" con istruzioni using separate? Per esempio. se si dispone di BinaryReader, è necessario disporre il flusso di risposta, che a sua volta dispone la risposta? Pensare a quell'ultima frase mi fa pensare che in realtà hai bisogno delle istruzioni using separate, perché non c'è modo di garantire che un oggetto wrapper possa disporre dell'oggetto interno. È giusto?

risposta

12

È necessario utilizzare istruzioni separate.

Nel secondo esempio, solo il BinaryReader verrà eliminato, non gli oggetti utilizzati per costruirlo.

Per vedere perché, guarda cosa fa effettivamente lo using statement. Si toglie il secondo codice, e fa qualcosa di equivalente a:

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

Come si può vedere, non ci sarebbe mai una chiamata Dispose() sul Response o ResponseStream.

+0

Hai bisogno di loro, ma non credo che debbano essere annidati. Penso che possano essere impilati uno sopra l'altro. –

+0

@Matt: Sì, ma devono esistere tutti e tre. –

+0

'BinaryReader.Close' chiude il flusso sottostante. E poiché 'Stream.Close' finisce per chiamare' Stream.Dispose', non è necessario chiudere lo stream dopo aver chiuso il lettore. Vedere http://msdn.microsoft.com/en-us/library/system.net.httpwebresponse.aspx e http://msdn.microsoft.com/en-us/library/system.io.stream.close.aspx . –

13

Si dovrebbe solo impilare le dichiarazioni utilizzando - ha l'effetto desiderato che stai cercando:

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

Questo è, in sostanza, lo stesso codice con diversa formattazione (rimuovendo solo le parentesi graffe). –

+0

Come questo migliora le cose, questo è effettivamente ciò che l'OP aveva solo meno le parentesi graffe che erano opzionali per le prime due istruzioni 'using'. – slugster

+0

Sì, è lo stesso, ma rispetto a quello che l'autore voleva sostituire con l'originale, questo è molto più facile da leggere e mantenere –

3

FWIW, ecco un altro modo di precisare il tuo esempio originale che può soddisfare qualsiasi sgomento per la nidificazione:

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

Se il lettore dispone del flusso è in realtà una funzione del lettore, non l''utilizzo'. Poiché ricordo che spesso è il comportamento dei lettori, essi prendono possesso del flusso e lo eliminano quando il lettore stesso viene chiuso. Ma il modulo che ho fornito sopra dovrebbe andare bene.

1

In base alla documentazione, BinaryReader.Close chiuderà il flusso sottostante. http://msdn.microsoft.com/en-us/library/system.io.binaryreader.close.aspx

Inoltre, in base alla documentazione per HttpWebResponse, è necessario chiudere lo stream sottostante o disporre la risposta. http://msdn.microsoft.com/en-us/library/system.net.httpwebresponse.aspx

Quindi il secondo esempio che hai fornito funzionerebbe.

+0

Grazie per la risposta ... Sospettavo che ci fossero altre possibilità. Immagino che nel dubbio, è meglio solo chiudere o eliminare tutto, a meno che tu non sappia cosa fa ogni tipo. –

0

L'ho postato altrove, ma separare le dichiarazioni con la virgola sembra trattare ogni istruzione separata in questo modo come una nuova dichiarazione e dispone di esse.

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

significa Questo però gli oggetti devono essere dello stesso tipo.li si potrebbe chiamare come

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

Ma poi, naturalmente, si ha accesso solo a metodi IDisposable, senza proiettare l'oggetto, che è un pò stupido. Così, invece, credo che si può utilizzare

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

Questo sembra dare i riferimenti agli oggetti correttamente digitati che consente l'accesso al corretto metodo del tipo assegnato, e dispone di entrambi gli oggetti creati. Se qualcuno sa perché non ho ragione, fammi sapere perché questo sembra funzionare per me? (So ​​che questa domanda è davvero vecchia, ma è tutto quello che ho potuto trovare mentre cercavo personalmente questa risposta)

Problemi correlati