2010-02-17 5 views
9

Questa è una domanda che mi sono posto molte volte in passato mentre ho annidato usando le istruzioni 5 in profondità.Tutti gli oggetti monouso istanziati all'interno di un blocco utilizza sono disposti?

Leggendo il docs e trovare alcuna menzione in entrambi i casi per quanto riguarda altri monouso istanziati all'interno del blocco ho deciso che era una buona Q per SO archivi.

Considerate questo:

using (var conn = new SqlConnection()) 
{ 
    var conn2 = new SqlConnection(); 
} 

// is conn2 disposed? 

risposta

6

Ovviamente non ho la risposta ... ;-)

La risposta è no. gli oggetti nella dichiarazione using sono disposti solo

[Test] 
public void TestUsing() 
{ 
    bool innerDisposed = false; 
    using (var conn = new SqlConnection()) 
    { 
     var conn2 = new SqlConnection(); 
     conn2.Disposed += (sender, e) => { innerDisposed = true; }; 
    } 

    Assert.False(innerDisposed); // not disposed 
} 

[Test] 
public void TestUsing2() 
{ 
    bool innerDisposed = false; 
    using (SqlConnection conn = new SqlConnection(), conn2 = new SqlConnection()) 
    { 
     conn2.Disposed += (sender, e) => { innerDisposed = true; }; 
    } 
    Assert.True(innerDisposed); // disposed, of course 
} 
+0

FYI: Ho ricevuto la risposta negli appunti prima di inviare la domanda. –

+0

Penso che sia tecnicamente possibile che quel thread venga sospeso in qualche modo tale che 'SqlConnection.Dispose()' venga chiamato da 'Component.Finalizer()' tra la variabile 'conn2' che esce dall'ambito e la linea' Assert' . C'è una condizione di gara qui, no? – binki

0

No. Controllare la IL generata con ILDASM o riflettore.

+0

sei troppo veloce per me per QnA me stesso .... –

14

No, non lo sono. Solo l'insieme di variabili esplicitamente elencate nella clausola using verrà automaticamente eliminato.

+1

Quindi dovrai nidificare in profondità 6 :-) –

+1

Immagino che tu abbia un fan club Jared .. lol .. –

0

Solo le variabili all'interno di using() verranno eliminate, non il blocco di codice effettivo. .

1

No. L'utilizzo fa spostare l'oggetto nell'istruzione using. Se si desidera che entrambi gli oggetti da smaltire, si dovrebbe riscrivere questo come:

using (var conn = new SqlConnection()) 
{ 
    using (var conn2 = new SqlConnection()) 
    { 
     // use both connections here... 
    } 
} 

O, in alternativa, è possibile utilizzare la sintassi più concisa:

using (SqlConnection conn = new SqlConnection(), conn2 = new SqlConnection()) 
{ 
    // use both connections here... 
} 
+4

Nota che puoi scrivere questo in modo più compatto. "using (SqlConn conn1 = new SqlConn(), conn2 = new SqlConn()) {stuff}" –

+0

Inoltre, un'istruzione 'using' piuttosto che un blocco (' using (var conn = new SqlConnection()) usando (var conn2 = new SqlConnection()) {...} ') sarà allineato bene in Visual Studio. Non indurrà il secondo "uso". –

+0

@Eric Lippert: ho aggiornato per mostrare anche quell'opzione ... @Jeffrey: Tendo a non farlo, come si lamenta StyleCop se non si usano le parentesi graffe per ogni istruzione. –

4

Se si desidera che le regole precise per l'istruzione using vede la sezione 8.13 della specifica. Tutte le tue domande dovrebbero essere chiaramente risposte lì.

+0

@eric, grazie per il riferimento. Ho postato questo Q dopo averlo scoperto con i test nella mia risposta più come servizio pubblico che altro. –

+2

@Eric: cura di fornire un collegamento alle specifiche, per coloro che non conoscono il modo di MSDN? –

+0

http://www.bing.com/search?q=c%23+specification –

2

No, non funziona, conn2 non verrà smaltito. Si noti che i multipli using sono l'unica situazione in cui non consentire l'utilizzo di staffe per più lisibility:

 using (var pen = new Pen(color, 1)) 
     using (var brush = new SolidBrush(color)) 
     using (var fontM60 = new Font("Arial", 15F, FontStyle.Bold, GraphicsUnit.Pixel)) 
     using (var fontM30 = new Font("Arial", 12F, FontStyle.Bold, GraphicsUnit.Pixel)) 
     using (var fontM15 = new Font("Arial", 12F, FontStyle.Regular, GraphicsUnit.Pixel)) 
     using (var fontM05 = new Font("Arial", 10F, FontStyle.Regular, GraphicsUnit.Pixel)) 
     using (var fontM01 = new Font("Arial", 8F, FontStyle.Regular, GraphicsUnit.Pixel)) 
     using (var stringFormat = new StringFormat()) 
     { 
     } 

In questo modo, annidato using non sono un grosso problema.