throw ve throw new Exception () arasındaki fark


164

arasındaki fark nedir

try { ... }
catch{ throw } 

ve

try{ ... }
catch(Exception e) {throw new Exception(e.message) } 

Ne olursa olsun ikinci bir mesaj gösterir?


51
İkinci pasaj, şimdiye kadar gördüğüm en kötü (ama zararsız) kod satırlarından biridir.
SLaks

Yanıtlar:


259

throw; orijinal istisnayı yeniden oluşturur ve orijinal yığın izini korur.

throw ex;orijinal istisnayı atar ancak catchbloğunuza kadar tüm yığın izleme bilgilerini yok ederek yığın izlemesini sıfırlar .


ASLA yazmathrow ex;


throw new Exception(ex.Message);daha da kötüdür. Exceptionİstisnanın orijinal yığın izini ve türünü kaybeden yepyeni bir örnek oluşturur . (ör IOException.).
Ayrıca, bazı istisnalar ek bilgiler içerir (ör ArgumentException.ParamName.).
throw new Exception(ex.Message); bu bilgiyi de yok edecektir.

Belirli durumlarda, özel bir istisna nesnesindeki tüm istisnaları sarmak isteyebilirsiniz, böylece istisna atıldığında kodun ne yaptığı hakkında ek bilgi sağlayabilirsiniz.

Bunu yapmak için, miras alan yeni bir sınıf tanımlayın Exception, dört istisna kurucusunun tümünü ve isteğe bağlı InnerExceptionolarak ek bilgilerin yanı sıra ek bilgi alan bir kurucu ekleyin ve parametre olarak ileterekexInnerException yeni istisna sınıfınızı atın . Orijinali ileterek InnerException, yığın izlemesi de dahil olmak üzere orijinal istisnanın tüm özelliklerini korursunuz.


24
"yeni İstisna (ex) atın; daha da kötüdür.": Buna katılmıyorum. Bazen bir istisnanın türünü değiştirmek ve ardından orijinal istisnayı iç istisna olarak tutmak, yapabileceğiniz en iyisidir. throw new MyCustomException(myMessage, ex);Tabii ki olmalı .
Dirk Vollmar

9
0xA3 @: Demek ex.Messageki, bir daha kötüsü.
SLaks

6
Standart kurucuları uygulamaya ek olarak, özel istisnalar da yapılmalıdır [Serializable()].
Dirk Vollmar

21
Hey, istisnaları seviyoruz, böylece istisnanızda bir istisna koyduk, böylece yakalarken yakalayabilirsiniz.
Darth Continent

2
@SLaks: Kural dışı throw;durumun oluştuğu gerçek satır numarası yerine satır numarası gelir throw;. Bunu nasıl ele almayı önerirsiniz? stackoverflow.com/questions/2493779/…
Eric J.

34

Birincisi orijinal yığın izini korur:

try { ... }
catch
{
    // Do something.
    throw;
}

İkincisi, istisnanın türünü ve / veya mesaj ve diğer verileri değiştirmenizi sağlar:

try { ... } catch (Exception e)
{
    throw new BarException("Something broke!");
}

İçsel bir istisnayı geçmenin üçüncü bir yolu da vardır:

try { ... }
catch (FooException e) {
    throw new BarException("foo", e);
} 

Şunu kullanmanızı öneririm:

  • ilki, bilgileri yok etmeden veya hata hakkında bilgi eklemeden hata durumunda bir miktar temizlik yapmak istiyorsanız.
  • üçüncü hata hakkında daha fazla bilgi eklemek istiyorsanız.
  • ikincisi bilgileri gizlemek istiyorsanız (güvenilmeyen kullanıcılardan).

6

Kimsenin görmediği bir nokta daha var:

Yakalama {} bloğunuzda hiçbir şey yapmazsanız, bir deneme ... yakalama anlamsızdır. Bunu her zaman görüyorum:

try 
{
  //Code here
}
catch
{
    throw;
}

Veya daha kötüsü:

try 
{
  //Code here
}
catch(Exception ex)
{
    throw ex;
}

En kötüsü:

try 
{
  //Code here
}
catch(Exception ex)
{
    throw new System.Exception(ex.Message);
}

Son maddeye sahip olmadığınız sürece katılıyorum.
Toni Rossmann

1
@ToniRossmann Bu durumda, atmaktan başka bir şey yapmadıkça try..finally catch olmadan kullanacağım;
JLWarlow

4

throwyakalanan kural dışı durumun throw new Exceptionbazı ayrıntılarını kaybederken , yığın izini koruyarak yakalanan kural dışı durumu yeniden atar .

Normalde, throwbir istisnayı o noktada tam olarak işlemeden kendi başına kaydetmek için kullanırsınız .

BlackWasp, C # 'da Özel Durumlar Atma başlıklı yeterince iyi bir makaleye sahiptir .


4

Yeni bir İstisna atmak mevcut yığın izini uçurur.

throw;orijinal yığın izini korur ve neredeyse her zaman daha kullanışlıdır. Bu kuralın istisnası, İstisnayı kendi özel bir İstisnasına sarmak istediğiniz zamandır. Daha sonra şunları yapmalısınız:

catch(Exception e)
{
    throw new CustomException(customMessage, e);
}

3

throwyakalanan bir istisnayı yeniden düzenlemek içindir. Bu, çağrı zincirini geçmeden önce istisna ile bir şeyler yapmak istiyorsanız yararlı olabilir.

throwBağımsız değişken olmadan kullanmak , çağrı yığınını hata ayıklama amacıyla korur.


0

İsterseniz orijinali iç istisna olarak ayarlanmış yeni bir İstisna atabilirsiniz.


0

İkinci örneğiniz, istisnanın yığın izlemesini sıfırlayacaktır. Birincisi, istisnanın kökenlerini en doğru şekilde korur. Ayrıca, aslında neyin yanlış gittiğini bilmenin anahtarı olan orijinal türü açtınız ... İkincisi işlevsellik için gerekiyorsa - örneğin, genişletilmiş bilgi eklemek veya özel bir 'HandleableException' gibi özel bir türle yeniden sarmak için InnerException özelliğinin de ayarlandığından emin olun!


Evet, bu hızlı yazmanız gereken sorulardan biri. ;)
Robert Harvey

0

En önemli fark, ikinci ifadenin istisna türünü silmesidir. İstisna türü, istisnaları yakalamada hayati bir rol oynar:

public void MyMethod ()
{
    // both can throw IOException
    try { foo(); } catch { throw; }
    try { bar(); } catch(E) {throw new Exception(E.message); }
}

(...)

try {
    MyMethod ();
} catch (IOException ex) {
    Console.WriteLine ("Error with I/O"); // [1]
} catch (Exception ex) {
    Console.WriteLine ("Other error");    // [2]
}

Eğer foo()atar IOException, [1]catch bloğu özel durum yakalayacak. Ama bar()fırlattığında IOException, düz Exceptionkarıncaya dönüştürülecek [1]catch bloğu tarafından yakalanmayacak.


0

atmak veya atmak, her ikisi de istisnayı atmak veya yeniden atmak için kullanılır, sadece hata bilgilerini günlüğe kaydettiğinizde ve herhangi bir bilgiyi arayan kişiye geri göndermek istemediğinizde, hatayı yakala ve bırak olarak kaydedersiniz. Ancak, atma veya atma kullandığınız arayan kişiye istisna hakkında bazı anlamlı bilgiler göndermek istiyorsanız. Şimdi atma ve atma arasındaki fark, atmanın yığın izini ve diğer bilgileri koruduğu, ancak ex'in yeni bir istisna nesnesi oluşturduğu ve dolayısıyla orijinal yığın izlemesinin kaybolmasıdır. Bu nedenle, atma ve atma e'yi ne zaman kullanmalıyız? Çağrı yığını bilgisini sıfırlamak gibi bir istisnayı yeniden yazmak isteyebileceğiniz birkaç durum var. Örneğin, yöntem bir kitaplıktaysa ve kitaplığın ayrıntılarını arama kodundan gizlemek istiyorsanız, çağrı yığınının kitaplıktaki özel yöntemler hakkında bilgi içermesini istemezsiniz. Bu durumda, kütüphanenin genel yöntemlerinde istisnalar yakalayabilir ve ardından çağrı yığını bu genel yöntemlerde başlayacak şekilde bunları yeniden oluşturabilirsiniz.


0

Atmak; Orijinal istisnayı yeniden oluşturun ve istisna türünü koruyun.

Yeni istisna () atın; Özgün istisna türünü geri alın ve istisna yığını izini sıfırlayın

Örn; İstisna yığını izini sıfırlayın ve istisna türünü sıfırlayın


-1

Buradaki cevapların hiçbiri, farkı anlamaya çalışan insanlar için yararlı olabilecek farkı göstermiyor. Bu örnek kodu düşünün:

using System;
using System.Collections.Generic;

namespace ExceptionDemo
{
   class Program
   {
      static void Main(string[] args)
      {
         void fail()
         {
            (null as string).Trim();
         }

         void bareThrow()
         {
            try
            {
               fail();
            }
            catch (Exception e)
            {
               throw;
            }
         }

         void rethrow()
         {
            try
            {
               fail();
            }
            catch (Exception e)
            {
               throw e;
            }
         }

         void innerThrow()
         {
            try
            {
               fail();
            }
            catch (Exception e)
            {
               throw new Exception("outer", e);
            }
         }

         var cases = new Dictionary<string, Action>()
         {
            { "Bare Throw:", bareThrow },
            { "Rethrow", rethrow },
            { "Inner Throw", innerThrow }
         };

         foreach (var c in cases)
         {
            Console.WriteLine(c.Key);
            Console.WriteLine(new string('-', 40));
            try
            {
               c.Value();
            } catch (Exception e)
            {
               Console.WriteLine(e.ToString());
            }
         }
      }
   }
}

Hangi aşağıdaki çıktıyı üretir:

Bare Throw:
----------------------------------------
System.NullReferenceException: Object reference not set to an instance of an object.
   at ExceptionDemo.Program.<Main>g__fail|0_0() in C:\...\ExceptionDemo\Program.cs:line 12
   at ExceptionDemo.Program.<>c.<Main>g__bareThrow|0_1() in C:\...\ExceptionDemo\Program.cs:line 19
   at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64

Rethrow
----------------------------------------
System.NullReferenceException: Object reference not set to an instance of an object.
   at ExceptionDemo.Program.<>c.<Main>g__rethrow|0_2() in C:\...\ExceptionDemo\Program.cs:line 35
   at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64

Inner Throw
----------------------------------------
System.Exception: outer ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at ExceptionDemo.Program.<Main>g__fail|0_0() in C:\...\ExceptionDemo\Program.cs:line 12
   at ExceptionDemo.Program.<>c.<Main>g__innerThrow|0_3() in C:\...\ExceptionDemo\Program.cs:line 43
   --- End of inner exception stack trace ---
   at ExceptionDemo.Program.<>c.<Main>g__innerThrow|0_3() in C:\...\ExceptionDemo\Program.cs:line 47
   at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64

Önceki cevaplarda belirtildiği gibi çıplak atma, hem başarısız olan orijinal kod satırını (satır 12) hem de istisna oluştuğunda çağrı yığınında aktif olan diğer iki noktayı (satır 19 ve 64) açıkça gösterir.

Yeniden atma kasasının çıktısı bunun neden bir sorun olduğunu gösterir. Kural dışı durum bu şekilde yeniden oluşturulduğunda kural dışı durum orijinal yığın bilgilerini içermez. Yalnızca throw e(hat 35) ve en dıştaki çağrı yığın noktasının (hat 64) dahil edildiğine dikkat edin. İstisnaları bu şekilde atarsanız, fail () yöntemini sorunun kaynağı olarak izlemek zor olacaktır.

Son durum (innerThrow) en ayrıntılı olanıdır ve yukarıdakilerden herhangi birinden daha fazla bilgi içerir. Yeni bir istisna oluşturduğumuzdan, içeriğe dayalı bilgiler ("dış" mesajı ekleyebiliyoruz, ancak burada yeni istisnada .Data sözlüğüne ekleyebiliriz) ve aynı zamanda orijinaldeki tüm bilgileri koruyabiliriz istisna (yardım bağlantıları, veri sözlüğü vb. dahil).

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.