2009-11-08 10 views

Odpowiedz

127

Konstrukcje

try { ... } 
catch() { ... } /* You can even omit the() here */ 

try { ... } 
catch (Exception e) { ... } 

są podobne, że zarówno złapie każdy wyjątek rzucony wewnątrz bloku try (i, chyba, że ​​są po prostu za to, aby zalogować się wyjątki, należy unikać). Spójrzmy teraz na te:

try { ... } 
catch() 
{ 
    /* ... */ 
    throw; 
} 

try { ... } 
catch (Exception e) 
{ 
    /* ... */ 
    throw; 
} 

try { ... } 
catch (Exception e) 
{ 
    /* ... */ 
    throw e; 
} 

Pierwsze i drugie bloki try-catch są dokładnie takie samo, po prostu przekaż bieżący wyjątek i że wyjątek zachowa swoje „źródła” i ślad stosu.

Trzeci blok catch try-catch jest inny. Kiedy zgłasza wyjątek, zmieni źródło i ślad stosu, tak że okaże się, że wyjątek został zgłoszony z tej metody, z tej samej linii throw e w metodzie zawierającej blok try-catch.

Którego powinieneś użyć? To naprawdę zależy od każdego przypadku.

Załóżmy, że masz klasę Person z metodą .Save(), która utworzy ją w bazie danych. Załóżmy, że Twoja aplikacja wykonuje gdzieś metodę Person.Save(). Jeśli twój DB odmówi zapisania Osoby, wtedy .Save() rzuci wyjątek. Czy w takim przypadku należy użyć throw lub throw e? Cóż, to zależy.

Co Wolę robi:

try { 
    /* ... */ 
    person.Save(); 
} 
catch(DBException e) { 
    throw new InvalidPersonException(
     "The person has an invalid state and could not be saved!", 
     e); 
} 

ten powinien umieścić DBException jako „wyjątek wewnętrzny” z nowszych wyjątkiem jest rzut.Tak więc podczas sprawdzania tego wyjątku InvalidPersonException ślad stosu będzie zawierał informacje z powrotem do metody Save (może to być wystarczające, aby rozwiązać problem), ale nadal masz dostęp do oryginalnego wyjątku, jeśli jest to potrzebne.

Jako ostatnia uwaga, jeśli jesteś spodziewa wyjątek, naprawdę powinieneś złapać że jednego określonego wyjątku, a nie ogólnym Exception, to znaczy, jeśli spodziewasz się InvalidPersonException powinien wolisz:

try { ... } 
catch (InvalidPersonException e) { ... } 

do

try { ... } 
catch (Exception e) { ... } 

Powodzenia!

30

Pierwsza zachowuje ślad stosu, a drugi go resetuje. Oznacza to, że jeśli użyjesz drugiego podejścia, ślad stosu wyjątku zawsze rozpocznie się od tej metody i utracisz oryginalny ślad wyjątku, który może być katastrofalny dla kogoś czytającego dzienniki wyjątków, ponieważ nigdy nie odkryje oryginalnej przyczyny wyjątku .

Drugie podejście może być przydatna, gdy chcemy dodać dodatkowe informacje do śledzenia stosu ale jest używany tak:

try 
{ 
    // do something 
} 
catch (Exception ex) 
{ 
    throw new Exception("Additional information...", ex); 
} 

Jest to blog post Omawiając różnice.

+0

Dobrze, że to świetna sprawa wiedzieć! – Myles

+0

dlaczego więc użyć drugiego? czy lepiej używać tylko pierwszego? – Karim

+1

Drugie przydaje się, gdy trzeba sprawdzić pod kątem określonych wyjątków - pojawia się OutOfRangeException - lub trzeba zalogować wiadomość itp. Pierwszy wydaje się być traktorem wyjątku wieloznacznym, podobnym do try {} catch (...) { } w C++. –

6

Należy użyć

try { } 
catch(Exception e) 
{ throw } 

jeśli chcesz coś zrobić z wyjątkiem przed ponownym wyrzuceniem go (zalogowaniu na przykład). Samotny rzut zachowuje ślad stosu.

+0

i co się stanie, jeśli zastąpię "rzut" tutaj "rzutem e"? – Karim

+3

Jak zauważył Darin, "throw e" zresetuje ślad stosu. –

4

Różnica między przechwytem bez parametrów a catch(Exception e) polega na uzyskaniu odwołania do wyjątku. Z wersji 2 programu zarządzanego wyjątki są opakowane w zarządzany wyjątek, więc wyjątek bez parametrów nie jest już przydatny do niczego.

Różnica między throw; a throw e; polega na tym, że pierwszy służy do ponownego wyrzucania wyjątków, a drugi służy do zgłaszania nowo utworzonego wyjątku. Jeśli użyjesz drugiego do ponownego wyrzucenia wyjątku, potraktuje to jak nowy wyjątek i zastąpi wszystkie informacje o stosie z miejsca, z którego został pierwotnie zgłoszony.

Więc, nie użyłeś żadnej z alternatywnych opcji w pytaniu. Nie powinieneś używać catchu bez parametrów i powinieneś użyć throw;, aby ponownie rzucić wyjątek.

W większości przypadków należy użyć bardziej szczegółowej klasy wyjątku niż klasa podstawowa dla wszystkich wyjątków. Powinieneś uchwycić tylko wyjątki, których się spodziewasz.

try { 
    ... 
} catch (IOException e) { 
    ... 
    throw; 
} 

Jeśli chcesz dodawać żadnych informacji kiedy Ponowne generowanie wyjątku, należy utworzyć nowy wyjątek z oryginalnym wyjątku jako wewnętrzna wyjątku preservere wszystkie informacje:

try { 
    ... 
} catch (IOException e) { 
    ... 
    throw new ApplicationException("Some informative error message", e); 
} 
Powiązane problemy