Apakah Buang masih dipanggil saat pengecualian dilemparkan ke dalam pernyataan using?

103

Dalam contoh di bawah ini, apakah koneksi akan ditutup dan dibuang ketika pengecualian dilemparkan jika berada dalam usingpernyataan?

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

Saya tahu kode di bawah ini akan memastikannya, tetapi saya ingin tahu bagaimana menggunakan pernyataan melakukannya.

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

Terkait:

Apa cara yang tepat untuk memastikan koneksi SQL ditutup saat pengecualian dilemparkan?

Brian Kim
sumber

Jawaban:

112

Ya, usingbungkus kode Anda dalam blok coba / akhirnya di mana finallybagian akan memanggil Dispose()jika ada. Namun, itu tidak akan memanggil Close()secara langsung karena hanya memeriksa IDisposableantarmuka yang diimplementasikan dan karenanya Dispose()metodenya.

Lihat juga:

Jeff Yates
sumber
5
Hanya untuk menunjukkan kelas koneksi jika Anda reflektor di atasnya, Anda akan melihat Dispose () memang secara internal memanggil Close (). Kalau dalam keadaan bisa.
Chris Marisic
2
Anda benar, itu benar. Namun, saya sengaja tidak menyebutkannya karena saya tidak ingin menyesatkan siapa pun untuk berpikir ini ada hubungannya dengan IDisposable atau pola terkait. Fakta bahwa implementasi khusus ini memanggil Close () adalah detail implementasi, bukan polanya.
Jeff Yates
3
MSDN menggunakan dokumentasi juga mengkonfirmasi jawaban ini: Pernyataan using memastikan bahwa Buang dipanggil bahkan jika pengecualian terjadi saat Anda memanggil metode pada objek. Anda dapat mencapai hasil yang sama dengan meletakkan objek di dalam blok percobaan dan kemudian memanggil Buang di blok akhirnya; sebenarnya, ini adalah bagaimana pernyataan using diterjemahkan oleh kompilator.
broadband
20

Beginilah cara reflektor mendekode IL yang dihasilkan oleh kode Anda:

private static void Main (string [] args)
{
    Koneksi SqlConnection = SqlConnection baru ("...");
    mencoba
    {
        samb.Open ();
        DoStuff ();
    }
    akhirnya
    {
        jika (samb! = null)
        {
            conn.Dispose ();
        }
    }
}

Jadi jawabannya ya, itu akan menutup koneksi jika

DoStuff ()
melempar pengecualian.

Florin Sabau
sumber
Tambahkan jika conn.Open () melontarkan pengecualian. : D
Jeff Yates
Ya, tentu. Jika apa pun yang ada di blok SETELAH klausa using melontarkan pengecualian, koneksi akan ditutup. Satu-satunya cara blok terakhir tidak akan dieksekusi adalah jika "new SqlConnection (...)" muncul, tetapi dalam kasus ini Anda tidak akan benar-benar memiliki koneksi terbuka yang valid untuk ditutup. Jadi tidak apa-apa.
Florin Sabau
-1

Dispose () tidak dipanggil dalam kode ini.

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();
    }
}
Chad
sumber
Apakah ini menjawab pertanyaan OP ??
Joey Phillips
Iya. Jawabannya adalah tidak. Dispose () tidak dipanggil dalam kode terlampir. Lebih jauh lagi pengecualian yang dilemparkan tidak ditangani dan program meledak.
Chad
Anda pasti melihat file yang salah. "Dispose ()" ditulis ke file temp Anda. Tidak ada yang mengklaim blok penggunaan akan menangani pengecualian. Coba jalankan ini tanpa debugger.
LarsTech
Saya menjalankan kode yang sama persis dan memanggil Dispose (). Anda yakin jawaban Anda benar?
Dnomyar96