Czy zagnieżdżone bloki Try / Catch to zły pomysł?

83

Powiedzmy, że mamy taką strukturę:

Try
  ' Outer try code, that can fail with more generic conditions, 
  ' that I know less about and might not be able to handle

  Try
    ' Inner try code, that can fail with more specific conditions,
    ' that I probably know more about, and are likely to handle appropriately
  Catch innerEx as Exception
    ' Handle the inner exception
  End Try

Catch outerEx as Exception
  ' Handle outer exception
End Try

Widziałem kilka opinii, że takie zagnieżdżanie Trybloków jest odradzane, ale nie mogłem znaleźć żadnych konkretnych powodów.

Czy to zły kod? Jeśli tak, dlaczego?

Goro
źródło
2
Nie wiem, jak dokładny jest ten fragment. Ale nie ma heckofalota, którego naprawdę wiesz, kiedy złapiesz Wyjątek. To może być wszystko . Rozważ wykorzystanie klauzuli When obsługiwanej przez VB.NET.
Hans Passant

Odpowiedzi:

86

Istnieją pewne okoliczności, w których są dobrym pomysłem, np. Jedna próba / przechwycenie dla całej metody, a druga w pętli, ponieważ chcesz obsłużyć wyjątek i kontynuować przetwarzanie pozostałej części kolekcji.

Naprawdę jedynym powodem, aby to zrobić, jest to, że chcesz pominąć bit, który popełnił błąd i kontynuować, zamiast rozwijać stos i tracić kontekst. Jednym z przykładów jest otwieranie wielu plików w edytorze.

To powiedziawszy, wyjątki powinny (jak sama nazwa wskazuje) być wyjątkowe. Program powinien je obsługiwać, ale starać się ich unikać w ramach normalnego przepływu wykonywania. Są kosztowne obliczeniowo w większości języków (Python jest jednym z wyjątków).

Inną techniką, która może być przydatna, jest przechwytywanie określonych typów wyjątków ...

Try
    'Some code to read from a file

Catch ex as IOException
    'Handle file access issues (possibly silently depending on usage)
Catch ex as Exception
    ' Handle all other exceptions.
    ' If you've got a handler further up, just omit this Catch and let the 
    ' exception propagate
    Throw
End Try

Używamy również zagnieżdżonych try / catches w naszych procedurach obsługi błędów ...

    Try
        Dim Message = String.Format("...", )
        Try
            'Log to database
        Catch ex As Exception
            'Do nothing
        End Try

        Try
            'Log to file
        Catch ex As Exception
            'Do nothing
        End Try
    Catch ex As Exception
        'Give up and go home
    End Try
Podstawowy
źródło
7
Logowanie w wątku w tle to miejsce, w którym użyję wewnętrznego try / catch. Nie chcę, aby metoda kończyła się, ponieważ nie mogła udokumentować tego, co robi.
gooch
@ Gooch prawda, ja też to robię, dodam to do mojej odpowiedzi.
Podstawowy
37

Właściwie nie sądzę, aby było coś z natury złego w zagnieżdżonych Try/ Catchblokach, z wyjątkiem tego, że mogą być trudne w nawigacji i prawdopodobnie są oznaką, że można dokonać refaktoryzacji (wewnętrzna Try/Catch do własnej metody).

Ale chcę odnieść się do tego komentarza:

' Outer try code, that can fail with more generic conditions, 
' that I know less about and might not be able to handle

Jeśli nie wiesz, jak sobie radzić z wyjątkami w konkretnej sytuacji, zaufaj mi: nie łapaj ich. Lepiej pozwolić swojej aplikacji na awarię (to znaczy, wiesz, zaloguj się; po prostu nie połykaj jej), niż złapać coś, z czego nie wiesz, jak odzyskać, a następnie pozwolić aplikacji kontynuować wesoło w stanie uszkodzonym . Od tego momentu zachowanie będzie w najlepszym przypadku nieprzewidywalne.

Dan Tao
źródło
To prawda. W momencie wyłapywania zewnętrznego wyjątku nie chciałbym kontynuować. Bardziej myślałem o tym, aby móc z wdziękiem zamknąć / ponownie uruchomić aplikację i nie szokować użytkownika „brzydką awarią”
Goro
10
@Goro: W takim przypadku zalecałbym mechanizm obsługi wyjątków dla całej aplikacji (np. Jeśli jest to WinForms, obsłuż Application.UnhandledExceptionzdarzenie) zamiast dla poszczególnych metod Try/ Catchbloków.
Dan Tao,