Dispose viene comunque chiamato quando viene generata un'eccezione all'interno di un'istruzione using?


103

Nell'esempio seguente, la connessione verrà chiusa e eliminata quando viene generata un'eccezione se si trova all'interno di usingun'istruzione?

using (var conn = new SqlConnection("..."))
{
    conn.Open();
    // stuff happens here and exception is thrown...
}

So che questo codice qui sotto farà in modo che lo faccia, ma sono curioso di sapere come lo fa l'istruzione using.

var conn;
try
{
    conn = new SqlConnection("...");
    conn.Open();
    // stuff happens here and exception is thrown...
}
// catch it or let it bubble up
finally
{
    conn.Dispose();
}

Relazionato:

Qual è il modo corretto per garantire che una connessione SQL venga chiusa quando viene generata un'eccezione?

Risposte:


112

5
Solo per sottolineare le classi di connessione se si riflette su di esse, si vedrà che Dispose () chiama internamente Close (). Se è in uno stato può.
Chris Marisic

2
Hai ragione, lo fa. Tuttavia, non l'ho deliberatamente menzionato perché non volevo indurre in errore nessuno a pensare che questo avesse qualcosa a che fare con IDisposable o con il pattern associato. Il fatto che questa particolare implementazione chiami Close () è un dettaglio dell'implementazione, non il pattern.
Jeff Yates,

3
MSDN using la documentazione conferma anche questa risposta: l'istruzione using garantisce che Dispose venga chiamato anche se si verifica un'eccezione durante la chiamata di metodi sull'oggetto. È possibile ottenere lo stesso risultato inserendo l'oggetto in un blocco try e quindi chiamando Dispose in un blocco finalmente; infatti, questo è il modo in cui l'istruzione using viene tradotta dal compilatore.
banda larga

20

Ecco come il riflettore decodifica l'IL generato dal tuo codice:

private static void Main (string [] args)
{
    SqlConnection conn = new SqlConnection ("...");
    provare
    {
        conn.Open ();
        Fare cose();
    }
    finalmente
    {
        if (conn! = null)
        {
            conn.Dispose ();
        }
    }
}

Quindi la risposta è sì, chiuderà la connessione se

Fare cose()
genera un'eccezione.


Aggiungi se conn.Open () genera un'eccezione. : D
Jeff Yates,

Si certo. Se qualunque cosa si trovi nel blocco DOPO la clausola using genera un'eccezione, la connessione verrà chiusa. L'unico modo in cui il blocco finalmente non verrà eseguito è se il "nuovo SqlConnection (...)" viene lanciato, ma in quel caso non avresti effettivamente una connessione aperta valida da chiudere. Quindi va bene.
Florin Sabau

-1

Dispose () non viene chiamato in questo codice.

class Program {
    static void Main(string[] args) {
        using (SomeClass sc = new SomeClass())
        {
            string str = sc.DoSomething();
            sc.BlowUp();
        }
    }
}

public class SomeClass : IDisposable {
    private System.IO.StreamWriter wtr = null;

    public SomeClass() {
        string path = System.IO.Path.GetTempFileName();
        this.wtr = new System.IO.StreamWriter(path);
        this.wtr.WriteLine("SomeClass()");
    }

    public void BlowUp() {
        this.wtr.WriteLine("BlowUp()");
        throw new Exception("An exception was thrown.");
    }

    public string DoSomething() {
        this.wtr.WriteLine("DoSomething()");
        return "Did something.";
    }

    public void Dispose() {
        this.wtr.WriteLine("Dispose()");
        this.wtr.Dispose();
    }
}

Questo risponde alla domanda OP ??
Joey Phillips

Sì. La risposta è no. Dispose () non viene chiamato nel codice allegato. Inoltre, l'eccezione generata non viene gestita e il programma esplode.
Ciad

Stai guardando il file sbagliato. "Dispose ()" viene scritto nel file temporaneo. Nessuno afferma che un blocco di utilizzo gestirà un'eccezione. Prova a eseguirlo senza un debugger.
LarsTech

Ho eseguito esattamente lo stesso codice e chiama Dispose (). Sei sicuro che la tua risposta sia corretta?
Dnomyar96
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.