Catch bloğundan bir istisna atarsanız, nihayet ne zaman çalıştırılır?


136
try {
   // Do stuff
}
catch (Exception e) {
   throw;
}
finally {
   // Clean up
}

Yukarıdaki blokta, en sonunda blok ne zaman çağrılır? E atmadan önce veya nihayet çağrılır ve sonra yakalanır?


14
ps "e atmamalısınız" çünkü bu, orijinal istisnanın yığın izini bozacaktır. Sadece "atmalısın;". Veya yeni bir istisna oluşturun ve InnerException'ı atmadan önce "e" olarak ayarlayın.
Erv Walter

24
Nihayet o çalıştırmak olmasaydı anahtar kelimenin oldukça kötü bir seçim olacağını son öyle değil mi?
Eric Lippert

@ErvWalter bu hala doğru mu? VS2017'de her iki şekilde de test ediyorum ve tamamen aynı görünüyor. Biraz daha bilgi veya referans verebilir misiniz? Teşekkürler
Jeff Puckett

sadece adlandırma önerisi kullanın İstisna istisnai - etkinlikler / delegeler için rezerve
bay R

Yanıtlar:


138

E yeniden atıldıktan sonra çağrılır (yani, catch bloğu çalıştırıldıktan sonra)

Bu 7 yıl sonra düzenleme - Bir önemli not ise olmasıdır eçağrı yığını daha yukarı bir try / catch bloğu tarafından yakalanan veya küresel bir özel durum işleyici değil, o finallyblok olabilir hiç yürütmek asla.


18
ve eğer Envrionment.FailFast () 'ı çağırmazsanız asla
Johannes Rudolph

16
Brandon'ın yanıtında kodunu denedikten sonra, görüyorum finallyönceki atılmış istisna ise, gerçekleştirilen DEĞİLDİR catchasla yakalanmış bir dış içinde try- catchbloğun!
Andrew

3
(Kabul edilen) yanıtınızı yeni bilgileri içerecek şekilde düzenlediğiniz için teşekkür ederiz.
Gordon Bean

3
Onlar (Microsoft) yeni dokümantasyon sitesinde bundan bahseder : docs.microsoft.com/en-us/dotnet/csharp/language-reference/… : " İşlenen bir istisna dahilinde, ilişkili en sonunda bloğunun çalıştırılması garanti edilir. Ancak , eğer istisna işlenmemişse, nihayet bloğunun yürütülmesi, istisna çözme işleminin nasıl tetiklendiğine bağlıdır. Bu da, bilgisayarınızın nasıl kurulduğuna bağlıdır. "
DotNetSparky

1
"Çağrı yığınının ilerisindeki bir dene / yakala bloğu tarafından yakalanan" ifadesinin, ASP.NET veya bir test çalıştırıcısında olanlar gibi çerçeve işleyicileri içereceğini unutmayın. Bunu ifade etmenin daha iyi bir yolu "programınız catch bloğundan sonra çalışmaya devam ederse, o zaman final bloğu çalışacaktır" olabilir.
ArrowCase

92

Neden denemiyorsun:

outer try
inner try
inner catch
inner finally
outer catch
outer finally

kodla (dikey boşluk için biçimlendirilmiş):

static void Main() {
    try {
        Console.WriteLine("outer try");
        DoIt();
    } catch {
        Console.WriteLine("outer catch");
        // swallow
    } finally {
        Console.WriteLine("outer finally");
    }
}
static void DoIt() {
    try {
        Console.WriteLine("inner try");
        int i = 0;
        Console.WriteLine(12 / i); // oops
    } catch (Exception e) {
        Console.WriteLine("inner catch");
        throw e; // or "throw", or "throw anything"
    } finally {
        Console.WriteLine("inner finally");
    }
}

5
+1, çok basit bir şey için, gerçekten Marc'ın yaptığı gibi denemelisin. Bunu iç içe geçmiş dene / yakala / nihayet gösteren GJ :)
Allen Rice

1
@AllenRice Marc zaten yapmışsa neden deneyin ve Marc'ın cevabını bulmak için sadece google yapabilirim? Ya da belki daha iyisi, kendinizi deneyin, sonra bir SO sorusu oluşturun ve başkalarının yararı için bunu kendiniz yanıtlayın.
joshden

8
Dış yakalamadaki istisnayı yakalayamazsanız, iç kısmın ASLA çalıştırılmayacağını lütfen unutmayın! Bu durumda çıktıouter try inner try inner catch Unhandled Exception: System.DivideByZeroException...
Andrew

1
@Andrew haklısın. Açıklamayı burada bulabilirsiniz MSDN Magazine 2008 Eylül: CLR'de İşlenmemiş Özel Durum İşleme (chm'yi açmak için kilidi açmanız gerekir: Dosya Özellikleri -> Genel -> Kilidi Aç). Dış yakalama bloğunu "catch (ArgumentException)" ile değiştirirseniz, CLR DivideByZeroException istisnasını işlemeyi kabul eden herhangi bir "istisna işleyici" bulamadığından, nihayetinde hiç kimse blok ilerlemeyecektir.
vladimir

35

Buradaki tüm cevapları okuduktan sonra, son cevap şuna bağlıdır :

  • Catch bloğu içinde yeniden bir istisna atarsanız ve bu istisna başka bir catch bloğunun içinde yakalanırsa, her şey belgelere göre yürütülür.

  • Bununla birlikte, re-trown istisnası işlenmezse, nihayet asla yürütülmez.

Bu kod örneğini VS2010 w / C # 4.0'da test ettim

static void Main()
    {
        Console.WriteLine("Example 1: re-throw inside of another try block:");

        try
        {
            Console.WriteLine("--outer try");
            try
            {
                Console.WriteLine("----inner try");
                throw new Exception();
            }
            catch
            {
                Console.WriteLine("----inner catch");
                throw;
            }
            finally
            {
                Console.WriteLine("----inner finally");
            }
        }
        catch
        {
            Console.WriteLine("--outer catch");
            // swallow
        }
        finally
        {
            Console.WriteLine("--outer finally");
        }
        Console.WriteLine("Huzzah!");

        Console.WriteLine();
        Console.WriteLine("Example 2: re-throw outside of another try block:");
        try
        {
            Console.WriteLine("--try");
            throw new Exception();
        }
        catch
        {
            Console.WriteLine("--catch");
            throw;
        }
        finally
        {
            Console.WriteLine("--finally");
        }

        Console.ReadLine();
    }

İşte çıktı:

Örnek 1: başka bir try bloğunun içine yeniden at:
--sonra dene
---- içsel deneme
---- içsel yakalama
---- içsel nihayet -
dıştan yakala
--sonunda
Huzzah!

Örnek 2: Başka bir try'ın yeniden atmak dışında:
--try
--catch

İşlenmeyen Özel Durum: System.Exception: 'System.Exception' türü özel durum oluştu.
ConsoleApplication1.Program.Main () konumunda C: \ local source \ ConsoleApplication1 \ Program.cs: satır 53


3
Harika yakalayış, bunun farkında değildim!
Andrew

1
Son olarak, seçtiğiniz şeye bağlı olarak çalışabileceğini unutmayın: stackoverflow.com/a/46267841/480982
Thomas Weller

1
İlginç ... .NET Core 2.0'da, en sonunda bölümü, işlenmemiş özel durumdan sonra çalışır.
Mahdi Ghiasi

Yeterince ilginç bir şekilde, hem .NET Core 2.0 hem de .NET Framework 4.6.1'de bir test yaptım ve ikisi de işlenmemiş istisnadan sonra nihayet çalışıyor. Bu davranış değişti mi?
Cameron Bielstein

24

Örneğiniz bu kodla aynı şekilde davranacaktır:

try {
    try {
        // Do stuff
    } catch(Exception e) {
        throw e;
    }
} finally {
    // Clean up
}

Bir yan not olarak, gerçekten kastetiyorsanız throw e;(yani, yakaladığınız aynı istisnayı atın), yeni bir yığın oluşturmak yerine orijinal yığın izini koruyacağından, bunu yapmak çok daha iyidir throw;.


Bunun doğru olduğunu sanmıyorum. Nihayet dış deneme bloğunun içinde olmalı, dışında
olmamalı

@MatthewPigram: Ne demek istiyorsun? finallyBlok aslında sonra yürüteceği catchbenim pasajı göstermek için çalışıyor budur bloğun (catch bloğu özel durum rethrows bile).
Daniel Pryden

Örneğini nasıl yorumladığımdan, sonunda başka bir try bloğu içinde bir try catch yapmaya çalışıyor. Sonunda deneme yakalamasında bir deneme değil
Matthew Pigram

1
@MatthewPigram: Cevabım "sonunda dene-yakala" yapısına sahip değil. Bir "dene-nihayet" var ve bu trybloğun içinde cevabımın bir "dene-yakala" var. 3 parçalı yapının davranışını iki parçalı yapı kullanarak açıklamaya çalışıyorum. tryOrijinal soruda ikinci bir blok olduğuna dair herhangi bir işaret görmüyorum , bu yüzden bunu nereden anladığınızı anlamıyorum.
Daniel Pryden

12

Bir catch işleyici bloğunun içinde işlenmemiş bir istisna varsa, final bloğu tam olarak sıfır kez çağrılır

  static void Main(string[] args)
  {
     try
     {
        Console.WriteLine("in the try");
        int d = 0;
        int k = 0 / d;
     }
     catch (Exception e)
     {
        Console.WriteLine("in the catch");
        throw;
     }
     finally
     {
        Console.WriteLine("In the finally");
     }
  }

Çıktı:

C: \ Users \ yönetici \ Belgeler \ TestExceptionNesting \ bin \ Release> TestExceptionNesting.exe

denemede

yakalamada

İşlenmeyen İstisna: System.DivideByZeroException: Sıfıra bölme denendi. C: \ users \ yönetici \ belgeler \ TestExceptionNesting \ TestExceptionNesting.cs: satır 22 içindeki TestExceptionNesting.Program.Main (String [] args)

C: \ Users \ yönetici \ Belgeler \ TestExceptionNesting \ bin \ release>

Bugün bir röportajda bu soruyu sordum ve görüşmeci geri dönüp durdu "sonunda aranmayacağından emin misin?" Bunun hileli bir soru mu yoksa mülakatı yapan kişinin aklında başka bir şey olup olmadığından ve hata ayıklamam için yanlış kod yazıp yazmadığından emin değildim, bu yüzden eve geldim ve denedim (inşa et ve çalıştır, hata ayıklayıcı etkileşimi yok), dinlenme.


Fırlatılan istisna yığının daha yüksek bir yerinde başka bir yakalamada yakalanmadıkça, bu durumda atılan istisna ele alınırsa çalıştırılabilir ... Ya da yanılıyor olabilirim ...
tomosius

@tomosius, evet, Brandon'ın cevabının açıklaması bu. :)
Andrew

@tomosius Bu yüzden "İşlenmemiş bir istisna varsa" belirterek başladım. Atılan istisna bir yerde yakalanmışsa, o zaman tanımı gereği farklı bir durumdan bahsediyoruz.
Eusebio Rufian-Zilbermann

Bu doğru değil. En azından NET Core 3.1 için değil. Bu koda sahip basit bir yeni konsol projesi, istisnadan sonra "sonunda" gösterir.
emzero

Davranışın değişmesi ilginçti, .NET çekirdeği yayınladığımda bile yoktu;)
Eusebio Rufian-Zilbermann

2

Bunu söylemenin basit bir yolu da kodunuzda hata ayıklamak ve sonunda ne zaman çağrıldığını fark etmektir.


1

Bir C # Konsol Uygulaması ile test edildiğinde, son kod, istisna atıldıktan sonra yürütüldü: "Uygulama Hatası İletişim Kutusu" mevcuttu ve "Programı kapat" seçeneğini seçtikten sonra, son blok o konsol penceresinde yürütüldü. Ama nihayet kod bloğunun içinde kırılma noktasını belirleyerek asla vuramam. Hata ayıklayıcı, throw deyiminde durmaya devam eder. İşte test kodum:

    class Program
    {
       static void Main(string[] args)
       {
          string msg;
          Console.WriteLine(string.Format("GetRandomNuber returned: {0}{1}", GetRandomNumber(out msg), msg) == "" ? "" : "An error has occurred: " + msg);
       }

       static int GetRandomNumber(out string errorMessage)
       {
         int result = 0;
         try
         {
            errorMessage = "";
            int test = 0;
            result = 3/test;
            return result;
         }
         catch (Exception ex)
         {
            errorMessage = ex.Message;
            throw ex;

         }
         finally
         {
            Console.WriteLine("finally block!");
         }

       }
    }

VS2010'da hata ayıklama - .NET Framework 4.0

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.