Yanıtlar:
Yapılar
try { ... }
catch () { ... } /* You can even omit the () here */
try { ... }
catch (Exception e) { ... }
her ikisi de try
bloğun içine atılan her istisnayı yakalayacağı için benzerdir (ve istisnaları günlüğe kaydetmek için bunu kullanmıyorsanız, kaçınılmalıdır ). Şimdi şunlara bakın:
try { ... }
catch ()
{
/* ... */
throw;
}
try { ... }
catch (Exception e)
{
/* ... */
throw;
}
try { ... }
catch (Exception e)
{
/* ... */
throw e;
}
Birinci ve ikinci try-catch blokları TAMAMEN aynı şeydir, sadece mevcut istisnayı yeniden atarlar ve bu istisna "kaynağını" ve yığın izini koruyacaktır.
Üçüncü try-catch bloğu farklıdır. İstisnayı attığında, kaynağı ve yığın izini değiştirecek, böylece istisnanın bu metottan, throw e
o try-catch bloğunu içeren metottaki satırdan atılmış gibi görünecektir .
Hangisini kullanmalısınız? Gerçekten her duruma göre değişir.
Diyelim ki, onu bir veritabanında saklayacak Person
bir .Save()
yönteme sahip bir sınıfınız var . Diyelim ki uygulamanız Person.Save()
yöntemi bir yerde çalıştırıyor . DB'niz Kişiyi kurtarmayı reddederse, .Save()
bir istisna atar. Kullanmak mı throw
yoksa throw e
bu durumda? Duruma göre değişir.
Yapmayı tercih ettiğim şey:
try {
/* ... */
person.Save();
}
catch(DBException e) {
throw new InvalidPersonException(
"The person has an invalid state and could not be saved!",
e);
}
Bu, DBException'ı yeni atılan istisnanın "İç İstisna" olarak koymalıdır. Bu nedenle, bu InvalidPersonException'ı incelediğinizde, yığın izleme, Save yöntemine kadar bilgi içerecektir (bu, sorunu çözmeniz için yeterli olabilir), ancak ihtiyacınız olursa orijinal özel duruma yine de erişebilirsiniz.
Son bir açıklama olarak, bir istisna beklediğinizde , genel olarak değil, belirli bir istisnayı gerçekten yakalamanız gerekir Exception
, yani, bir InvalidPersonException bekliyorsanız, tercih etmelisiniz:
try { ... }
catch (InvalidPersonException e) { ... }
-e
try { ... }
catch (Exception e) { ... }
İyi şanslar!
Birincisi yığın izini korurken, ikincisi onu sıfırlar. Bu, ikinci yaklaşımı kullanırsanız, istisnanın yığın izlemesinin her zaman bu yöntemden başlayacağı ve istisna günlüklerini okuyan biri için istisnanın orijinal nedenini asla bulamayacağı için felaket olabilecek orijinal istisna izini kaybedeceğiniz anlamına gelir. .
İkinci yaklaşım, yığın izlemesine ek bilgi eklemek istediğinizde yararlı olabilir, ancak şu şekilde kullanılır:
try
{
// do something
}
catch (Exception ex)
{
throw new Exception("Additional information...", ex);
}
Farklılıkları tartışan bir blog yazısı var .
throw
vs throw e
.
Kullanmalısın
try { }
catch(Exception e)
{ throw }
yeniden atmadan önce istisna ile bir şey yapmak istiyorsanız (örneğin günlüğe kaydetme). Yalnız atış, yığın izini korur.
Parametresiz catch ile a arasındaki fark catch(Exception e)
, istisnaya bir referans almanızdır. Çerçeve sürüm 2'den yönetilmeyen istisnalar, yönetilen bir istisnaya sarılır, bu nedenle parametresiz istisna artık hiçbir şey için yararlı değildir.
Arasındaki fark throw;
ve throw e;
ilki istisnalar rethrow için kullanılır ve ikinci bir yeni oluşturulan özel durum için kullanılır olmasıdır. İkincisini bir istisnayı yeniden atmak için kullanırsanız, buna yeni bir istisna gibi davranacak ve tüm yığın bilgilerini orijinal olarak atıldığı yerden değiştirecektir.
Bu nedenle, söz konusu alternatiflerden hiçbirini kullanmamalısınız. Parametresiz yakalama kullanmamalısınız throw;
ve bir istisnayı yeniden atmak için kullanmalısınız .
Ayrıca, çoğu durumda, tüm istisnalar için temel sınıftan daha spesifik bir istisna sınıfı kullanmalısınız. Yalnızca beklediğiniz istisnaları yakalamalısınız.
try {
...
} catch (IOException e) {
...
throw;
}
İstisnayı yeniden atarken herhangi bir bilgi eklemek isterseniz, tüm bilgileri korumak için bir iç istisna olarak orijinal istisna ile yeni bir istisna oluşturursunuz:
try {
...
} catch (IOException e) {
...
throw new ApplicationException("Some informative error message", e);
}