Częste błędy w programowaniu in.Net podczas obsługi wyjątków? [zamknięte]

Jakie są najczęstsze błędy popełniane podczas obsługi wyjątków?

Wydaje się, że obsługa wyjątków może być jedną z najtrudniejszych rzeczy do nauczenia się, jak robić "dobrze" w .Net. szczególnie biorąc pod uwagę obecnie #1 w rankingu odpowiedź na typowe błędy programistyczne dla programistów. NET, aby uniknąć? jest związane z obsługą WYJĄTKÓW.

Mam nadzieję, że wymieniając niektóre z najczęstszych błędów, wszyscy nauczymy się lepiej radzić sobie z wyjątkami.

Author: jColeson, 2010-05-21

14 answers

Jakie są najczęstsze błędy popełniane podczas obsługi wyjątków?

Myślę o wielu rzeczach.

Najpierw Przeczytaj mój artykuł o kategoryzacji WYJĄTKÓW do , boneheaded, śmiertelne i egzogenne :

Http://ericlippert.com/2008/09/10/vexing-exceptions/

Niektóre typowe błędy:

  • nieprzestrzeganie egzogennych WYJĄTKÓW.
  • Brak obsługi irytacji wyjątki.
  • Budowa metod rzucających irytujące wyjątki.
  • Obsługa wyjątków, z którymi nie można sobie poradzić, jak fatalne wyjątki.
  • Obsługa wyjątków, które ukrywają błędy w kodzie; nie obsługuj WYJĄTKÓW, Napraw błąd tak, aby nie został wyrzucony w pierwszej kolejności

  • Błąd bezpieczeństwa: brak trybu niebezpiecznego

    try
    {
      result = CheckPassword();
      if (result == BadPassword) throw BadPasswordException();
    }
    catch(BadPasswordException ex) { ReportError(ex); return; }
    catch(Exception ex) { LogException(ex); }
    AccessUserData();
    
    Widzisz, co się stało? Nie udało nam się przejść do niebezpiecznego trybu. Jeśli checkpassword rzucił NetworkDriverIsAllMessedUpException następnie złapaliśmy go, zalogowaliśmy i uzyskaliśmy dostęp do danych użytkownika niezależnie od tego, czy hasło było poprawne. Nie w trybie awaryjnym; gdy pojawi się jakikolwiek wyjątek, Załóżmy najgorsze.
  • Błąd bezpieczeństwa: produkcja wyjątków, które wyciekają poufne informacje , bezpośrednio lub pośrednio.

    Nie chodzi dokładnie o obsługę wyjątków w Twoim kodzie, ale o tworzenie wyjątków, które są obsługiwane przez wrogie kod.

    Zabawna historia. Przed wysłaniem. NET 1.0 do klientów znaleźliśmy błąd, w którym możliwe było wywołanie metody, która wyrzuciła wyjątek "zespół, który wywołał tę metodę, nie ma uprawnień do określenia nazwy pliku C:\foo.txt". Świetnie. Dzięki za informację. Co powstrzymuje wspomniane Zgromadzenie przed przechwyceniem wyjątku i przesłuchaniem jego wiadomości, aby uzyskać nazwę pliku? Nic. Naprawiliśmy to przed wysłaniem. To jest bezpośredni problem. Problem pośredni problem byłby zaimplementowany w LoadPicture, w VBScript. To dało inny komunikat o błędzie w zależności od tego, czy niepoprawnym argumentem jest katalog, plik, który nie jest obrazkiem, czy plik, który nie istnieje. Co oznacza, że możesz go używać jako bardzo powolnej przeglądarki dyskowej! Wypróbowując całą masę różnych rzeczy, możesz stopniowo budować obraz tego, jakie pliki i katalogi znajdowały się na czyimś dysku twardym. Wyjątki powinny być tak skonstruowane, że jeśli są obsługiwane przez nierzetelny kod, to kod nie uczy się żadnych prywatnych informacji użytkownika z tego, co zrobił, aby spowodować wyjątek. (LoadPicture daje teraz znacznie mniej pomocnych komunikatów o błędach.)
  • Błąd bezpieczeństwa i zarządzania zasobami: programy obsługi, które nie czyszczą zasobów, czekają na wycieki zasobów . Wycieki zasobów mogą być używane jako ataki typu denial-of-service przez wrogi częściowy kod zaufania, który celowo tworzy wyjątki-produkując sytuacje.

  • Robustness error: Handleers must assume that program state is buried up unless handling a specific exogenic exception. Jest to szczególnie prawdziwe w przypadku wreszcie bloków. Kiedy obsługujesz nieoczekiwany wyjątek, jest całkowicie możliwe, a nawet prawdopodobne, że coś jest głęboko popaprane w twoim programie. Nie masz pojęcia, czy któryś z Twoich podsystemów działa, a jeśli tak, to czy ich wywołanie poprawi lub pogorszy sytuację. Skoncentruj się na rejestrowanie błędu i zapisywanie danych użytkownika, jeśli to możliwe, i wyłączanie tak czysto, jak to możliwe. Załóżmy, że nic nie działa dobrze.

  • Błąd bezpieczeństwa: tymczasowe mutacje stanu globalnego, które mają wpływ na bezpieczeństwo, muszą zostać cofnięte przed każdy kod, który może być wrogi może uruchomić. Wrogi kod może uruchomić przed wreszcie bloki uruchomić! Zobacz mój artykuł na ten temat dla szczegóły:

Http://blogs.msdn.com/ericlippert/archive/2004/09/01/224064.aspx

 44
Author: Eric Lippert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-28 16:12:12

Ponowne rzucanie WYJĄTKÓW w ten sposób:

try 
{ 
   // some code here
}
catch(Exception ex)
{
   // logging, etc
   throw ex;
}

To zabija ślad stosu, Tworzenie jest znacznie mniej użyteczne. Prawidłowa droga do rethrow będzie taka:

try 
{ 
   // some code here
}
catch(Exception ex)
{
   // logging, etc
   throw;
}
 25
Author: Adam Lear,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-21 16:51:31

Wyłapywanie wszystkich wyjątków, gdy w wielu przypadkach powinieneś spróbować wyłapać konkretne wyjątki:

try {
  // Do something.
} catch (Exception exc) {
  // Do something.
}

Zamiast:

try {
  // Do something.
} catch (IOException exc) {
  // Do something.
}

Wyjątki powinny być uporządkowane od najbardziej konkretnego do najmniej.

 12
Author: Jay Riggs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-21 16:55:00

Przemyślenie wyjątku z bezsensowną wiadomością.

try
{
    ...
}
catch (Exception ex)
{
   throw new Exception("An error ocurred when saving database changes").
}
Nie uwierzysz, jak często widzę taki kod w produkcji.
 10
Author: CARLOS LOTH,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-21 17:15:01

Nikt nie mówi o takich pustych blokach....

 try{  
      //do something
    }
catch(SQLException sqex){  
        // do nothing  
    }

Również nigdy nie używaj obsługi wyjątków do tworzenia alternatywnych przepływów metod...

 try{  
     //do something  

 }catch(SQLException sqex){  

     //do something else  
 }
 9
Author: Srikar Doddi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-21 18:00:30

Nieużywanie using na IDisposable obiektach :

File myFile = File.Open("some file");
callSomeMethodWhichThrowsException(myFile);
myFile.Close();

MyFile nie zostanie zamknięte, dopóki nie zostanie wywołany finalizer myFile (co może nigdy nie być), ponieważ wyjątek został wyrzucony przed wywołaniem myFile.Close().

Właściwym sposobem na to jest

using(File myFile = File.Open("some file"))
{
    callSomeMethodWhichThrowsException(myFile);
}

To zostaje przetłumaczone przez kompilator na coś w rodzaju:

File myFile = File.Open("some file");
try
{
    callSomeMethodWhichThrowsException(myFile);
}
finally
{
    if(myFile != null)
        myFile.Dispose(); //Dispose() calls Close()
}

Więc plik zostaje zamknięty nawet w obliczu WYJĄTKÓW.

 7
Author: BlueRaja - Danny Pflughoeft,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-21 18:34:27

Zapomnij ustawić wewnętrzny wyjątek, gdy zmienisz przechwycony wyjątek

try
{
    ...
}
catch (IOException ioException)
{
    throw new AppSpecificException("It was not possible to save exportation file.")
    // instead of
    throw new AppSpecificException("It was not possible to save exportation file.", ioException);
}

Kiedy zamieszczałem tę odpowiedź, zapominam wspomnieć, że zawsze powinniśmy rozważyć, kiedy włączyć wewnętrzny wyjątek, czy nie ze względów bezpieczeństwa. Jak Eric Lippert zwrócił uwagę na inną odpowiedź na ten temat, niektóre wyjątki mogą dostarczyć poufnych informacji o szczegółach implementacji serwera. Tak więc, jeśli rozmówca, który będzie obsługiwał wyjątek, nie jest zaufany, nie jest dobrym pomysłem jest włączenie wewnętrznych informacji o wyjątkach.

 6
Author: CARLOS LOTH,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:07:55

Empty catch:

//What's the point?
catch()
{}

:

//Exceptions are for *adding* detail up the stack
catch (Exception ex)
{throw ex;}
 4
Author: Dave Swersky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-21 16:51:12

Założenie wyjątku obejmującego wiele scenariuszy było czymś szczególnym. Prawdziwym scenariuszem była aplikacja internetowa, w której obsługa wyjątków zawsze zakładała, że wszystkie błędy są przerwami w sesji, a rejestrowane i zgłaszane wszystkie błędy jako przerwy w sesji.

Inny przykład:

try
{
     Insert(data);
}
catch (SqlException e)
{
   //oh this is a duplicate row, lets change to update
   Update(data);
}
 3
Author: MatthewMartin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-21 17:17:35

To log Exception.Wiadomość zamiast wyjątku.ToString ()

Wiele razy widzę rejestrowanie kodu tylko komunikat wyjątku, podczas gdy powinien on rejestrować powrót metody ToString. ToString dostarcza znacznie więcej informacji o wyjątku niż wiadomość. Zawiera informacje takie jak wewnętrzny wyjątek i ślad stosu oprócz wiadomości.

 3
Author: CARLOS LOTH,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-21 17:21:12

Próba wyłapania OutOfMemoryExceptionlub StackOverflowException - prowadzą one do zamknięcia runtime ' u, a więc do wyłapania ich z tego samego procesu (a nawet z CLR jako całości?)

OutOfMemoryException: wyjątek, który jest wyrzucany, gdy nie ma wystarczającej ilości pamięci, aby kontynuować wykonywanie programu.

"począwszy od. NET Framework w wersji 2.0, obiekt StackOverflowException nie może zostać przechwycony przez blok try-catch i odpowiedni proces jest domyślnie zakończony. W związku z tym zaleca się użytkownikom pisanie kodu, aby wykryć i zapobiec przepełnieniu stosu."

 1
Author: Michael Stum,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-21 17:44:43

Brak wyłapania możliwych WYJĄTKÓW wewnątrz funkcji obsługi. Może to spowodować, że niewłaściwy wyjątek będzie propagowany w górę.

Na przykład:

try
{
    DoImportantWork();
}
catch
{
    Cleanup();        
    throw;
}

Co się stanie, jeśli Cleanup() rzuci wyjątek? Nie chcesz widzieć wyjątku wskazującego na metodę Cleanup () w tym programie obsługi przechwytywania. Chcesz oryginalny błąd. Możesz spróbować zarejestrować błąd czyszczenia, ale nawet Twój kod logowania wymaga obsługi wyjątków, aby uniknąć wyrzucania z niego WYJĄTKÓW.

try
{
    DoImportantWork();
}
catch
{
    try
    {
        Cleanup();        
    }
    catch
    {
        // We did our best to clean up, and even that failed.
        // If you try to log this error, the logging may throw yet another Exception.
    }
    throw;
}
 1
Author: Paul Williams,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-21 18:47:55

Wrong

try
{
   // Do something stupid
}
catch
{
   // ignore the resulting error because I'm lazy, and later spend
   // a week trying to figure out why my app is crashing all over
   // the place.
}

Lepiej

try
{
    /// do something silly.
}
catch (InvalidOperationException ex)
{
    /// respond, or log it.
}
catch (Exception e)
{
    /// log it.
}
 0
Author: 3Dave,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-21 17:01:12

Używanie wyjątków dla normalnej kontroli przepływu. Wyjątki powinny być wyjątkowe. Jeśli jest to operacja dobra / oczekiwana, użyj wartości zwracanych, itd.

 0
Author: Donnie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-21 18:34:21