İfadeyi kullanmanın sonuna gelmeden dönersem ne olur? Elden çıkarma çağrılacak mı?


115

Aşağıdaki koda sahibim

using(MemoryStream ms = new MemoryStream())
{
     //code
     return 0;
}

dispose()Yöntem sonunda denir usingparantez deyimi }doğru mu? I yana returnbitmeden usingaçıklamada, olacak MemoryStreamnesne düzgün bertaraf edilmesi? Burada ne oluyor?


4
@JonH: Tam kopyasını bulun ve bu durumda lütfen kapatmak için oy verin.
Noldorin

@Noldorin: Bu konuda bir dupe aramaya gittim, çünkü daha önce sorulmuş olmalı diye düşündüm , ama bulamadım. Sanırım orada hala kolay sorular var. :)
Randolpho

@JonH ve @Noldorin - soru oluştuğunda kopyalar sunulacaktı, "benzer sorular" arıyor, insanların yeterince kullanmadığı bir özellik.
Adam Houldsworth

@Adam: git kendin dene. Başlığı kopyalayın / yapıştırın ve sistem tarafından hangi kopyaların sunulacağını görün. Size bir ipucu vereceğim: cevap yok. Google veya SO'nun araması yoluyla arama yaparsanız aynen. Görünüşe göre bu soru daha önce sorulmamış.
Randolpho

Aaap ... Onu geri alıyorum. Çok özel bir aramadan sonra neredeyse bir kopyasını buldum: stackoverflow.com/questions/2641692/… Şimdi, soru tamamen farklı soruluyor, ancak nihai soru hemen hemen aynı. Sanırım bunu bir kukla olarak görebiliriz.
Randolpho

Yanıtlar:


167

Evet, Disposearanacak. Yürütme, usingbloğun kapsamını terk eder etmez, bloğu terk etmenin ne anlama geldiğine bakılmaksızın, bloğun yürütülmesinin sonu, bir returnifade veya bir istisna olabilir.

@Noldorin doğru bir şekilde kullanılarak işaret ettiği gibi, usingkod bloğu içine derlenmiş try/ finallyile Disposede çağrılan finallyblok. Örneğin aşağıdaki kod:

using(MemoryStream ms = new MemoryStream())
{
     //code
     return 0;
}

etkili bir şekilde şu hale gelir:

MemoryStream ms = new MemoryStream();
try
{
    // code
    return 0;
}
finally
{
    ms.Dispose();
}

Bu nedenle, bloğun yürütülmesi bittikten finallysonra tryyürütülmesi Disposegarantilidir , yürütme yoluna bakılmaksızın, ne olursa olsun çağrılması garanti edilir.

Daha fazla bilgi için bu MSDN makalesine bakın .

Ek:
Eklemek için küçük bir uyarı: Disposeçağrılması garantili olduğundan , Disposeuygularken asla bir istisna oluşturmamasını sağlamak neredeyse her zaman iyi bir fikirdir IDisposable. Ne yazık ki, çekirdek kitaplığında bazı sınıflar vardır yapmak bazı durumlarda atmak Disposesana bakıyorum, WCF Servis Referans / İstemci proxy - denir! - ve bu olduğunda, Disposebir istisna yığını çözülme sırasında çağrılmışsa , orijinal istisnayı bulmak çok zor olabilir , çünkü orijinal istisna, Disposeçağrı tarafından oluşturulan yeni istisna lehine yutulur . Çıldırtıcı derecede sinir bozucu olabilir. Yoksa sinir bozucu bir şekilde çıldırtıcı mı? İkinin biri. Belki ikisi de.


4
Sanırım bunun Dispose, sonunda bir arama ile bir dene-sonunda bloğunda etkili bir şekilde derlendiğini göreceksiniz , bu yüzden finally, tarif ettiğiniz gibi, etkin bir şekilde uygulanması üzerinde çalışıyor .
Noldorin

@Noldorin: aynen. Yine de bu konuda açık olabilirim. Yakında düzenlenecek ....
Randolpho

1
Ayrıca, Environment.FailFast kullanımı ve bir StackOverFlowException meydana gelmesi gibi, final bloğunun yürütülmesinin garanti edilmediği bazı durumlar olduğunu unutmayın.
Christopher McAtackney

@ C.McAtackney: aynı zamanda iyi bir nokta. Ayrıca IIRC, OutOfMemoryException; temelde kritik bir yürütme hatası olduğu için istisnayı yakalayamazsanız, Dispose çağrılmaz. Elbette, böyle bir durumda, programın kendisine ayrılan herhangi bir bellekle birlikte çökmesi garanti edilir, bu nedenle, dispose yönteminizde bir dosyaya yazmak gibi riskli şeyler yapmadığınız sürece, vakaların% 99,9'unda sorun teşkil etmez. . Feci program çökmesinin yanı sıra, yani.
Randolpho

WCF ile 'using ()' ifadesini asla kullanmamalısınız - daha fazla bilgi için bu makaleye bakın . İşte WCF proxy'leri için kullandığım bir pasaj: 'WCFProxy variableName = null; {variableName = new WCFProxy () deneyin; // TODO kodu burada variableName.Proxy.Close (); variableName.Dispose (); } catch (Exception) {if (variableName! = null && variableName.Proxy! = null) {variableName.Proxy.Abort (); } atmak; } '
Dave Black

18

usingdeyimler tam olarak try ... finallybloklar gibi davranır , bu nedenle her zaman herhangi bir kod çıkış yolunda çalıştırılır. Bununla birlikte, finallyblokların çağrılmadığı çok az ve nadir durumlara maruz kaldıklarına inanıyorum . Hatırlayabildiğim bir örnek, arka plan iş parçacığı etkinken ön plan iş parçacığının çıkıp finallyçıkmadığıdır: GC dışındaki tüm iş parçacıkları duraklatılır, yani bloklar çalıştırılmaz.

Apaçık düzenleme: IDisposable nesneleri işlemelerine izin veren mantık dışında aynı şekilde davranırlar, d'oh.

Bonus içerik: istiflenebilirler (türlerin farklı olduğu yerlerde):

using (SqlConnection conn = new SqlConnection("string"))
using (SqlCommand comm = new SqlCommand("", conn))
{

}

Ayrıca virgülle ayrılmış (türlerin aynı olduğu durumlarda):

using (SqlCommand comm = new SqlCommand("", conn), 
       SqlCommand comm2 = new SqlCommand("", conn))
{

}

4

MemoryStream nesneniz uygun şekilde atılacaktır, bunun için endişelenmenize gerek yoktur.



0

Kodunuzu derledikten sonra reflektördeki kodunuza bir göz atın. Derleyicinin, dispose işleminin akışta çağrıldığından emin olmak için kodu yeniden düzenlediğini göreceksiniz.

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.