Bir using ifadesinin içine istisna atıldığında Dispose hala çağrılıyor mu?


103

Aşağıdaki örnekte, bir usingifadenin içindeyse bir istisna atıldığında bağlantı kapanacak ve elden çıkarılacak mı?

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

Aşağıdaki kodun işe yarayacağını biliyorum, ancak ifadenin bunu nasıl yaptığını merak ediyorum.

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

İlişkili:

Bir istisna atıldığında bir SQL bağlantısının kapatılmasını sağlamanın doğru yolu nedir?

Yanıtlar:


112

Evet, usingkodunuzu, varsa finallybölümün arayacağı bir dene / nihayet bloğuna sarar Dispose(). Bununla birlikte, Close()yalnızca IDisposableuygulanan arayüzü ve dolayısıyla Dispose()yöntemi kontrol ettiği için doğrudan çağırmaz .

Ayrıca bakınız:


5
Sadece bağlantı sınıflarına işaret etmek için, eğer onların üzerinde yansıtıcı olursanız, göreceksiniz ki Dispose () gerçekten Close () 'u dahili olarak çağırıyor. Eğer bir durumda ise yapabilir.
Chris Marisic

2
Haklısın, öyle. Bununla birlikte, bunun IDisposable veya ilişkili modelle bir ilgisi olduğunu düşünmek için kimseyi yanıltmak istemediğim için kasıtlı olarak bahsetmedim. Bu özel uygulamanın Close () 'u çağırması, modelin değil, uygulamanın bir detayıdır.
Jeff Yates

3
Belgeleri kullanan MSDN, bu yanıtı da doğrular: using ifadesi, nesnede yöntemleri çağırırken bir istisna oluşsa bile Dispose'un çağrılmasını sağlar. Aynı sonucu, nesneyi bir try bloğunun içine yerleştirip ardından bir last bloğunda Dispose çağırarak da elde edebilirsiniz; aslında, bu, kullanım deyiminin derleyici tarafından nasıl çevrildiğidir.
geniş bant

20

Reflektör, kodunuz tarafından üretilen IL'nin kodunu şu şekilde çözer:

özel statik void Ana (dize [] değiştirgeler)
{
    SqlConnection bağlantısı = new SqlConnection ("...");
    Deneyin
    {
        conn.Open ();
        Şeyler yapmak();
    }
    en sonunda
    {
        eğer (bağ! = boş)
        {
            conn.Dispose ();
        }
    }
}

Yani cevap evet, eğer

Şeyler yapmak()
bir istisna atar.


Conn.Open () bir istisna atarsa ​​ekleyin. : D
Jeff Yates

Evet tabi. Using cümlesi bir istisna atarsa, blokta ne varsa, bağlantı kapatılacaktır. Nihayet bloğunun yürütülmemesinin tek yolu, "yeni SqlConnection (...)" atarsa, ancak bu durumda kapatmak için gerçekten geçerli bir açık bağlantınız olmayacaktır. Yani sorun değil.
Florin Sabau

-1

Dispose () bu kodda çağrılmaz.

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

Bu OP sorusuna cevap veriyor mu?
Joey Phillips

Evet. Cevap hayır. Dispose () ekli kodda çağrılmaz. Dahası, fırlatılan istisna ele alınmaz ve program patlar.
Çad

Yanlış dosyaya bakıyor olmalısın. Geçici dosyanıza "Dispose ()" yazılır. Hiç kimse bir kullanım bloğunun bir istisnayı ele alacağını iddia etmez. Bunu bir hata ayıklayıcı olmadan çalıştırmayı deneyin.
LarsTech

Bu aynı kodu çalıştırdım ve Dispose () çağırıyor. Cevabınızın doğru olduğundan emin misiniz?
Dnomyar96
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.