Najważniejsze wskazówki dotyczące obsługi wyjątków w aplikacji Windows Forms?

118

Obecnie jestem w trakcie pisania mojej pierwszej aplikacji Windows Forms. Przeczytałem teraz kilka książek o języku C #, więc mam stosunkowo dobre zrozumienie, jakie funkcje języka C # ma do czynienia z wyjątkami. Wszystkie są dość teoretyczne, ale nie mam jeszcze pojęcia, jak przełożyć podstawowe pojęcia na dobry model obsługi wyjątków w mojej aplikacji.

Czy ktoś chciałby podzielić się jakąś mądrością na ten temat? Opublikuj wszelkie typowe błędy, które popełnili nowicjusze tacy jak ja, oraz wszelkie ogólne porady dotyczące obsługi wyjątków w sposób, który zapewni stabilność i niezawodność mojej aplikacji.

Główne rzeczy, nad którymi obecnie pracuję, to:

  • Kiedy należy ponownie zgłosić wyjątek?
  • Czy powinienem spróbować mieć jakiś centralny mechanizm obsługi błędów?
  • Czy obsługa wyjątków, które mogą być generowane, ma spadek wydajności w porównaniu z testowaniem z wyprzedzeniem, takim jak sprawdzenie, czy plik na dysku istnieje?
  • Czy cały kod wykonywalny powinien być zamknięty w blokach try-catch-last?
  • Czy są sytuacje, w których pusty blok catch może być akceptowalny?

Wszystkie rady otrzymane z wdzięcznością!

Jon Artus
źródło

Odpowiedzi:

79

Jeszcze kilka bitów ...

Absolutnie powinieneś mieć scentralizowaną politykę obsługi wyjątków. Może to być tak proste, jak zawinięcie Main()próby / złapania, które kończy się niepowodzeniem i wyświetla użytkownikowi wdzięczny komunikat o błędzie. To jest "ostatnia deska ratunku" do obsługi wyjątków.

Kontrole wyprzedzające są zawsze poprawne, jeśli są wykonalne, ale nie zawsze są doskonałe. Na przykład między kodem, w którym sprawdzasz istnienie pliku, a następnym wierszem, w którym go otwierasz, plik mógł zostać usunięty lub inny problem może utrudniać dostęp. Nadal musisz spróbować / złapać / wreszcie w tym świecie. Użyj odpowiednio wyprzedzającego czeku i try / catch / final.

Nigdy nie „połykaj” wyjątków, z wyjątkiem najlepiej udokumentowanych przypadków, kiedy jesteś absolutnie, pozytywnie pewien, że rzucany wyjątek jest znośny. To prawie nigdy nie będzie miało miejsca. (A jeśli tak, upewnij się, że połykasz tylko określoną klasę wyjątków - nigdy nie połykaj System.Exception).

Podczas budowania bibliotek (używanych przez twoją aplikację) nie połykaj wyjątków i nie bój się, że wyjątki będą się rozwijać. Nie rzucaj ponownie, chyba że masz coś przydatnego do dodania. Nigdy (w C #) nie rób tego:

throw ex;

Jak będziesz wymazać stos wywołań. Jeśli musisz ponownie przesłać (co jest czasami konieczne, na przykład podczas korzystania z bloku obsługi wyjątków w bibliotece korporacyjnej), użyj:

throw;

Ostatecznie ogromna większość wyjątków generowanych przez uruchomioną aplikację powinna gdzieś zostać ujawniona. Nie powinny być ujawniane użytkownikom końcowym (ponieważ często zawierają zastrzeżone lub w inny sposób cenne dane), ale raczej powinny być rejestrowane, a administratorzy powiadamiani o wyjątku. Aby uprościć sprawę, użytkownikowi można wyświetlić ogólne okno dialogowe, na przykład z numerem referencyjnym.

Obsługa wyjątków w .NET to bardziej sztuka niż nauka. Każdy będzie miał tutaj swoje ulubione. To tylko kilka wskazówek, które wykorzystałem .NET od pierwszego dnia, techniki, które uratowały mój boczek niejednokrotnie. Twój przebieg może się różnić.

John Rudy
źródło
1
Jeśli pozwolisz, aby wyjątki się pojawiały, w jaki sposób dzwoniący ma wiedzieć, czy wyjątek wskazuje, że operacja się nie powiodła, ale system jest zasadniczo w porządku (np. Użytkownik próbował otworzyć uszkodzony plik dokumentu; plik się nie ładuje, ale wszystko inaczej powinno być dobrze), czy też wskazuje, że procesor się pali i należy jak najszybciej udać się do wyjść? Coś w rodzaju ArgumentException może również wskazywać, w zależności od okoliczności, w których jest rzucany.
supercat
2
@supercat Pisząc określone podklasy ApplicationExceptiondla tych przypadków awarii, które aplikacja powinna być w stanie rozróżnić i obsłużyć.
Matt Enright,
@Matt Enright: Z pewnością można wyłapać własne wyjątki, ale nie jestem świadomy niczego, co mogłoby przypominać konwencję, według której moduły rzucające wyjątki wskazują, czy wskazują na zepsucie dowolnego stanu poza tym, co jest sugerowane przez awarię. W idealnym przypadku metoda taka jak SuperDocument.CreateFromFile () zakończyłaby się sukcesem, zgłosiłaby wyjątek CleanFailure lub zgłosiłaby wyjątek SomethingReallyBadHappenedException. Niestety, o ile nie zawinie się wszystkiego, co może rzucić wyjątek we własnym bloku catch, nie ma sposobu, aby dowiedzieć się, czy
wyjątek InvalidOperationException
@Matt Enright: ... powinien być opakowany w wyjątek CleanFailureException lub SomethingReallyBadHappenedException. A pakowanie wszystkiego w pojedyncze bloki try-catch zniweczyłoby cały cel posiadania wyjątków.
supercat
2
Myślę, że to kiepski projekt biblioteki, aby ukryć tryby awarii za pomocą niedokładnego typu wyjątku. Nie zgłaszaj wyjątku FileNotFoundException, jeśli w rzeczywistości masz na myśli wyjątek IOException lub InvalidDataException, ponieważ aplikacja musi inaczej reagować na każdy przypadek. Rzeczy takie jak StackOverflowException lub OutOfMemoryException nie mogą być obsługiwane przez aplikację, więc po prostu pozwól im bąbelkować, ponieważ dobrze zachowana aplikacja i tak ma scentralizowaną procedurę obsługi „ostatniej szansy”.
Matt Enright
63

Jest tutaj doskonały artykuł dotyczący kodu CodeProject . Oto kilka najważniejszych informacji:

  • Zaplanuj najgorsze *
  • Sprawdź to wcześnie
  • Nie ufaj zewnętrznym danym
  • Jedynymi niezawodnymi urządzeniami są: wideo, mysz i klawiatura.
  • Pisanie też może się nie udać
  • Koduj bezpiecznie
  • Nie wyrzucaj nowego wyjątku ()
  • Nie umieszczaj ważnych informacji o wyjątku w polu Wiadomość
  • Umieść jeden zaczep (wyjątek ex) na wątek
  • Wychwycone ogólne wyjątki powinny zostać opublikowane
  • Log Exception.ToString (); nigdy nie rejestruj tylko wyjątku.Wiadomość!
  • Nie przechwytuj (wyjątku) więcej niż raz na wątek
  • Nigdy nie połykaj wyjątków
  • Kod porządkujący należy umieścić w końcowych blokach
  • Używaj wszędzie „using”
  • Nie zwracaj specjalnych wartości w przypadku błędów
  • Nie używaj wyjątków do wskazywania braku zasobu
  • Nie używaj obsługi wyjątków jako sposobu zwracania informacji z metody
  • Użyj wyjątków dla błędów, których nie należy ignorować
  • Nie czyść śladu stosu podczas ponownego zgłaszania wyjątku
  • Unikaj zmiany wyjątków bez dodawania wartości semantycznej
  • Wyjątki powinny być oznaczone [serializowalny]
  • W przypadku wątpliwości nie zgłaszaj wyjątku
  • Każda klasa wyjątków powinna mieć co najmniej trzy oryginalne konstruktory
  • Zachowaj ostrożność podczas używania zdarzenia AppDomain.UnhandledException
  • Nie odkrywaj na nowo koła
  • Nie używaj nieustrukturyzowanej obsługi błędów (VB.Net)
Micheasza
źródło
3
Czy mógłbyś wyjaśnić mi nieco więcej tego punktu? „Nie używaj wyjątków do wskazania braku zasobu” Nie jestem pewien, czy rozumiem przyczynę takiego stanu rzeczy. Tylko uwaga: ta odpowiedź w ogóle nie wyjaśnia „dlaczego”. Wiem, że to ma 5 lat, ale wciąż mnie to trochę
niepokoi
Link do artykułu, którego dotyczy odwołanie, wygasł. Code Project sugeruje, że artykuł mógł zostać przeniesiony tutaj .
DavidRR,
15

Zauważ, że Windows Forms ma własny mechanizm obsługi wyjątków. Jeśli przycisk w formularzu zostanie kliknięty, a jego program obsługi zgłosi wyjątek, który nie zostanie przechwycony w programie obsługi, Windows Forms wyświetli własne okno dialogowe nieobsługiwanego wyjątku.

Aby zapobiec wyświetlaniu okna dialogowego nieobsłużonych wyjątków i przechwytywaniu takich wyjątków w celu rejestrowania i / lub udostępniania własnego okna dialogowego błędu, można dołączyć do zdarzenia Application.ThreadException przed wywołaniem Application.Run () w metodzie Main ().

user95680
źródło
Dzięki za sugestię, dowiedziałem się tego za późno, właśnie zweryfikowałem to w linqpadzie, działa zgodnie z oczekiwaniami, delegatem jest: void Form1_UIThreadException (object sender, ThreadExceptionEventArgs t) Kolejnym dobrym źródłem na ten temat jest richnewman.wordpress.com/2007/ 04/08 /… W przypadku ogólnej obsługi nieobsłużonych wyjątków: zdarzenie AppDomain.UnhandledException jest dla nieobsłużonych wyjątków zgłoszonych z wątku innego niż główny interfejs użytkownika.
zhaorufei
14

Wszystkie dotychczas zamieszczone rady są dobre i warte uwagi.

Jedną z rzeczy, które chciałbym rozwinąć, jest twoje pytanie: „Czy obsługa wyjątków, które mogą być generowane, powoduje spadek wydajności w porównaniu z testami wyprzedzającymi, takimi jak sprawdzenie, czy plik na dysku istnieje?”

Naiwna zasada brzmi: „bloki try / catch są drogie”. To nie jest prawda. Próbowanie nie jest drogie. Jest to łapanie, w którym system musi utworzyć obiekt Exception i załadować go ze śladem stosu, jest to kosztowne. Istnieje wiele przypadków, w których wyjątek jest na tyle wyjątkowy, że można umieścić kod w bloku try / catch.

Na przykład, jeśli wypełniasz słownik, to:

try
{
   dict.Add(key, value);
}
catch(KeyException)
{
}

jest często szybszy niż to:

if (!dict.ContainsKey(key))
{
   dict.Add(key, value);
}

dla każdego dodawanego elementu, ponieważ wyjątek jest zgłaszany tylko wtedy, gdy dodajesz zduplikowany klucz. (Robią to zapytania agregujące LINQ).

W podanym przykładzie użyłbym try / catch prawie bez zastanowienia. Po pierwsze, tylko dlatego, że plik istnieje, gdy go sprawdzasz, nie oznacza, że ​​będzie istniał, gdy go otworzysz, więc i tak powinieneś naprawdę obsłużyć wyjątek.

Po drugie, i myślę, że co ważniejsze, chyba że a) twój proces otwiera tysiące plików i b) prawdopodobieństwo, że plik, który próbuje otworzyć, a nie istnieje, nie jest trywialnie niski, wydajność tworzenia wyjątku nie jest czymś, co Ty '' kiedykolwiek zauważysz. Ogólnie rzecz biorąc, gdy program próbuje otworzyć plik, próbuje otworzyć tylko jeden plik. To przypadek, w którym pisanie bezpieczniejszego kodu prawie na pewno będzie lepsze niż pisanie najszybszego możliwego kodu.

Robert Rossney
źródło
3
w przypadku dict[key] = value
dict'a
9

Oto kilka wskazówek, których się trzymam

  1. Szybka awaria: jest to raczej wskazówka dotycząca generowania wyjątków. Dla każdego przyjętego założenia i każdego parametru, który dostajesz do funkcji, sprawdź, czy zaczynasz od właściwych danych i że założenia robione są poprawne. Typowe sprawdzenia obejmują, argument nie jest pusty, argument w oczekiwanym zakresie itp.

  2. Podczas ponownego rzucania zachowaj ślad stosu - to po prostu przekłada się na użycie throw podczas ponownego rzucania zamiast rzucania new Exception (). Alternatywnie, jeśli uważasz, że możesz dodać więcej informacji, zawiń oryginalny wyjątek jako wyjątek wewnętrzny. Ale jeśli łapiesz wyjątek tylko po to, aby go zarejestrować, zdecydowanie użyj opcji throw;

  3. Nie wychwytuj wyjątków, których nie możesz obsłużyć, więc nie przejmuj się takimi rzeczami, jak OutOfMemoryException, ponieważ jeśli wystąpią, i tak nie będziesz w stanie wiele zrobić.

  4. Przechwyć globalne programy obsługi wyjątków i upewnij się, że rejestrujesz jak najwięcej informacji. W przypadku winforms przechwyć zarówno zdarzenia wyjątków appdomain, jak i wątków.

  5. Wydajność należy brać pod uwagę tylko wtedy, gdy przeanalizowałeś kod i zobaczyłeś, że powoduje wąskie gardło wydajności, domyślnie optymalizuj pod kątem czytelności i projektu. Więc jeśli chodzi o twoje pierwotne pytanie dotyczące sprawdzania istnienia pliku, powiedziałbym, że to zależy.Jeśli możesz coś zrobić z brakiem pliku, to tak, zrób to, w przeciwnym razie, jeśli wszystko, co zamierzasz zrobić, to zgłosić wyjątek, jeśli plik jest nie tam, nie widzę sensu.

  6. Zdecydowanie zdarzają się sytuacje, w których wymagane są puste bloki catch. Myślę, że ludzie, którzy twierdzą inaczej, nie pracowali nad bazami kodu, które ewoluowały w ciągu kilku wydań. Ale należy je skomentować i przejrzeć, aby upewnić się, że są naprawdę potrzebne. Najbardziej typowym przykładem są programiści używający try / catch do konwersji ciągu znaków na liczbę całkowitą zamiast używania ParseInt ().

  7. Jeśli oczekujesz, że obiekt wywołujący Twojego kodu będzie w stanie obsłużyć warunki błędu, utwórz niestandardowe wyjątki, które szczegółowo określają, jaka jest nietypowa sytuacja i dostarczają odpowiednich informacji. W przeciwnym razie po prostu trzymaj się wbudowanych typów wyjątków tak bardzo, jak to możliwe.

Sijin
źródło
Jaki jest pożytek z przechwytywania zarówno appdomain, jak i obsługi nieobsługiwanych wyjątków wątku? Jeśli używasz po prostu Appdomain.UnhandledException, czy nie jest to najbardziej ogólny, który złapie wszystko?
Quagmire
Czy chodziło Ci o obsłużenie Application.ThreadExceptionzdarzenia, gdy odwołujesz się do zdarzenia „nieobsługiwany wyjątek wątku”?
Jeff B
4

Podoba mi się filozofia polegająca na tym, że nie łapię niczego, z czym nie mam zamiaru sobie poradzić, bez względu na sposób obsługi w moim konkretnym kontekście.

Nienawidzę, gdy widzę kod taki jak:

try
{
   // some stuff is done here
}
catch
{
}

Widziałem to od czasu do czasu i dość trudno jest znaleźć problemy, gdy ktoś „zjada” wyjątki. Współpracownik, z którym miałem do czynienia, robił to i zwykle kończy się na tym, że wnosi wkład w stały strumień problemów.

Rzucam ponownie, jeśli jest coś, co moja konkretna klasa musi zrobić w odpowiedzi na wyjątek, ale problem musi zostać przekazany do metody, w której to się stało.

Uważam, że kod powinien być napisany proaktywnie, a wyjątki powinny dotyczyć wyjątkowych sytuacji, a nie unikać testowania warunków.

itsmatt
źródło
@Kiquenet Przepraszamy, byłem trochę niejasny. Co miałem na myśli: nie rób takich pustych połowów, zamiast tego dodaj procedurę obsługi do Dispatcher.UnhandledException i dodaj przynajmniej dziennik, aby nie był zjadany bez bułki tartej :) Ale jeśli nie masz wymogu cichego komponentu, zawsze powinieneś uwzględniać wyjątki do swojego projektu. Rzucaj je, gdy trzeba je wyrzucić, twórz jasne kontrakty dla siebie Interfejsy / API / dowolna klasa.
LuckyLikey
4

Właśnie wychodzę, ale krótko omówię, gdzie używać obsługi wyjątków. Po powrocie postaram się odnieść do pozostałych punktów :)

  1. Jawnie sprawdź wszystkie znane warunki błędów *
  2. Dodaj try / catch wokół kodu, jeśli nie masz pewności, czy poradziłeś sobie ze wszystkimi przypadkami
  3. Dodaj try / catch wokół kodu, jeśli wywoływany interfejs .NET zgłasza wyjątek
  4. Dodaj try / catch wokół kodu, jeśli przekracza on próg złożoności
  5. Dodaj próbę / złapanie wokół kodu, jeśli chcesz sprawdzić poczytalność: Zapewniasz, że TO NIGDY NIE POWINNO SIĘ ZDARZYĆ
  6. Z reguły nie używam wyjątków jako zamiennika kodów zwrotnych. To jest dobre dla .NET, ale nie dla mnie. Mam jednak wyjątki (hehe) od tej reguły, zależy to również od architektury aplikacji, nad którą pracujesz.

*W granicach rozsądku. Nie ma potrzeby sprawdzania, czy powiedzmy, że promień kosmiczny uderzył w twoje dane, powodując odwrócenie kilku bitów. Zrozumienie, co jest „rozsądne”, jest umiejętnością nabytą przez inżyniera. Trudno to określić ilościowo, ale łatwo się intuicyjnie. Oznacza to, że mogę łatwo wyjaśnić, dlaczego używam metody try / catch w jakimkolwiek konkretnym przypadku, ale trudno mi przyswoić inną tę samą wiedzę.

Po pierwsze, mam tendencję do odchodzenia od architektur opartych na wyjątkach. metoda try / catch nie ma trafienia związanego z wydajnością jako takiego, trafienie pojawia się, gdy zostanie zgłoszony wyjątek, a kod może być zmuszony przejść przez kilka poziomów stosu wywołań, zanim coś go obsłuży.

pezi_pink_squirrel
źródło
4

Złota zasada, której próbowaliśmy się trzymać, polega na obsługiwaniu wyjątku jak najbliżej źródła.

Jeśli musisz ponownie zgłosić wyjątek, spróbuj dodać do niego wyjątek, ponowne zgłoszenie wyjątku FileNotFoundException nie pomaga zbytnio, ale zgłoszenie wyjątku ConfigurationFileNotFoundException pozwoli na jego przechwycenie i wykonanie działania w dowolnym miejscu w łańcuchu.

Inną zasadą, którą staram się przestrzegać, jest to, aby nie używać try / catch jako formy przepływu programu, więc sprawdzam pliki / połączenia, upewniam się, że obiekty zostały zainicjowane, itd. Przed ich użyciem. Try / catch powinno być dla wyjątków, rzeczy, których nie możesz kontrolować.

Jeśli chodzi o pusty blok catch, jeśli robisz coś ważnego w kodzie, który wygenerował wyjątek, powinieneś co najmniej ponownie zgłosić wyjątek. Jeśli nie ma żadnych konsekwencji kodu, który spowodował, że wyjątek nie został uruchomiony, dlaczego napisałeś go w pierwszej kolejności.


źródło
Ta „złota zasada” jest w najlepszym przypadku arbitralna.
Evan Harper,
3

możesz przechwycić zdarzenie ThreadException.

  1. Wybierz projekt aplikacji systemu Windows w Eksploratorze rozwiązań.

  2. Otwórz wygenerowany plik Program.cs, klikając go dwukrotnie.

  3. Dodaj następujący wiersz kodu na początku pliku kodu:

    using System.Threading;
  4. W metodzie Main () dodaj następujący wiersz jako pierwszy wiersz metody:

    Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
  5. Dodaj poniższy tekst poniżej metody Main ():

    static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
    {
        // Do logging or whatever here
        Application.Exit();
    }
  6. Dodaj kod, aby obsłużyć nieobsługiwany wyjątek w programie obsługi zdarzeń. Każdy wyjątek, który nie jest obsługiwany nigdzie indziej w aplikacji, jest obsługiwany przez powyższy kod. Najczęściej ten kod powinien rejestrować błąd i wyświetlać komunikat użytkownikowi.

odniesienie: https://blogs.msmvps.com/deborahk/global-exception-handler-winforms/

Omid-RH
źródło
@Kiquenet przepraszam, nie wiem o VB
Omid-RH
2

Wyjątki są drogie, ale konieczne. Nie musisz pakować wszystkiego w try catch, ale musisz upewnić się, że wyjątki zawsze zostaną ostatecznie złapane. Wiele z nich będzie zależało od twojego projektu.

Nie rzucaj ponownie, jeśli pozwolenie na powstanie wyjątku będzie równie dobre. Nigdy nie pozwól, aby błędy minęły niezauważone.

przykład:

void Main()
{
  try {
    DoStuff();
  }
  catch(Exception ex) {
    LogStuff(ex.ToString());
  }

void DoStuff() {
... Stuff ...
}

Jeśli DoStuff pójdzie nie tak, i tak chcesz, aby został zwolniony za kaucją. Wyjątek zostanie wyrzucony do main i zobaczysz ciąg zdarzeń w śladzie stosu ex.

Echostorm
źródło
1

Kiedy należy ponownie zgłosić wyjątek?

Wszędzie, ale metody użytkownika końcowego ... takie jak programy obsługi kliknięć przycisków

Czy powinienem spróbować mieć jakiś centralny mechanizm obsługi błędów?

Piszę plik dziennika ... całkiem proste dla aplikacji WinForm

Czy obsługa wyjątków, które mogą być generowane, ma spadek wydajności w porównaniu z testowaniem z wyprzedzeniem, takim jak sprawdzenie, czy plik na dysku istnieje?

Nie jestem tego pewien, ale uważam, że dobrą praktyką jest rzucanie wyjątków ... Mam na myśli, że możesz zapytać, czy plik istnieje i czy nie zgłasza wyjątku FileNotFoundException

Czy cały kod wykonywalny powinien być zamknięty w blokach try-catch-last?

yeap

Czy są sytuacje, w których pusty blok catch może być akceptowalny?

Tak, powiedzmy, że chcesz pokazać datę, ale nie masz pojęcia, w jaki sposób ta data była przechowywana (dd / mm / rrrr, mm / dd / rrrr itp.), Próbujesz ją przeanalizować, ale jeśli się nie powiedzie, po prostu kontynuuj. ... jeśli to nie ma dla ciebie znaczenia ... powiedziałbym, że tak, jest

sebagomez
źródło
1

Jedyną rzeczą, której nauczyłem się bardzo szybko, było zamknięcie absolutnie każdego fragmentu kodu, który wchodzi w interakcje z czymkolwiek poza przepływem mojego programu (tj. System plików, wywołania bazy danych, dane wejściowe użytkownika) blokami try-catch. Try-catch może spowodować spadek wydajności, ale zwykle w tych miejscach w kodzie nie będzie to zauważalne i zwróci się bezpiecznie.

Użyłem pustych bloków catch w miejscach, w których użytkownik może zrobić coś, co nie jest naprawdę „niepoprawne”, ale może zgłosić wyjątek ... przykład, który przychodzi na myśl, jest w GridView, jeśli użytkownik DoubleCLicks jest szary symbol zastępczy komórka w lewym górnym rogu uruchomi zdarzenie CellDoubleClick, ale komórka nie należy do wiersza. W takim razie nie naprawdę trzeba wysłać wiadomość, ale jeśli jej nie złapiesz, wyśle ​​do użytkownika nieobsłużony błąd wyjątku.

BKimmel
źródło
1

Podczas ponownego zgłaszania wyjątku słowo kluczowe rzuca samodzielnie. Spowoduje to zgłoszenie przechwyconego wyjątku i nadal będzie można użyć śledzenia stosu, aby zobaczyć, skąd pochodzi.

Try
{
int a = 10 / 0;
}
catch(exception e){
//error logging
throw;
}

wykonanie tej czynności spowoduje, że ślad stosu zakończy się w instrukcji catch. (unikaj tego)

catch(Exception e)
// logging
throw e;
}
Brad8118
źródło
Czy to nadal dotyczy najnowszych wersji .NET Framework i .NET Core?
LuckyLikey
1

Z mojego doświadczenia uznałem za stosowne wyłapać wyjątki, kiedy wiem, że zamierzam je tworzyć. W przypadku, gdy jestem w aplikacji internetowej i wykonuję Response.Redirect, wiem, że otrzymam wyjątek System.ThreadAbortException. Ponieważ jest to zamierzone, po prostu złapałem określony typ i po prostu go połknąłem.

try
{
/*Doing stuff that may cause an exception*/
Response.Redirect("http:\\www.somewhereelse.com");
}
catch (ThreadAbortException tex){/*Ignore*/}
catch (Exception ex){/*HandleException*/}
Jeff Keslinke
źródło
1

Głęboko zgadzam się z zasadą:

  • Nigdy nie pozwól, aby błędy minęły niezauważone.

Powód jest taki, że:

  • Kiedy po raz pierwszy będziesz zapisywać kod, najprawdopodobniej nie będziesz miał pełnej wiedzy na temat kodu firm zewnętrznych, biblioteki .NET FCL lub najnowszych wkładów współpracowników. W rzeczywistości nie możesz odmówić napisania kodu, dopóki nie poznasz dobrze każdej możliwości wyjątku. Więc
  • Stale uważam, że używam try / catch (Exception ex) tylko dlatego, że chcę się chronić przed nieznanymi rzeczami i, jak zauważyłeś, łapię Exception, a nie bardziej szczegółowe, takie jak OutOfMemoryException itp. I zawsze robię wyjątek wyskakujące do mnie (lub QA) przez ForceAssert.AlwaysAssert (false, ex.ToString ());

ForceAssert.AlwaysAssert to moja osobista droga do Trace.Assert, niezależnie od tego, czy zdefiniowano makro DEBUG / TRACE.

Być może cykl rozwoju: zauważyłem brzydkie okno dialogowe Assert lub ktoś inny narzeka mi na to, potem wracam do kodu i znajduję powód, dla którego należy zgłosić wyjątek i decyduję, jak go przetworzyć.

W ten sposób mogę napisać MÓJ kod w krótkim czasie i ochronić mnie przed nieznaną domeną, ale zawsze będąc zauważonym, jeśli zdarzy się coś nienormalnego, w ten sposób system stał się bezpieczny i bardziej bezpieczny.

Wiem, że wielu z was nie zgodzi się ze mną, ponieważ programista powinien znać każdy szczegół swojego kodu, szczerze mówiąc, w dawnych czasach jestem też purystą. Ale teraz dowiedziałem się, że powyższa polityka jest bardziej pragmatyczna.

W przypadku kodu WinForms złota zasada, której zawsze przestrzegam, to:

  • Zawsze próbuj / catch (wyjątek) swój kod obsługi zdarzeń

Dzięki temu Twój interfejs użytkownika będzie zawsze użyteczny.

W przypadku osiągnięcia wydajności spadek wydajności występuje tylko wtedy, gdy kod osiągnie catch, wykonanie kodu try bez rzeczywistego podniesionego wyjątku nie ma znaczącego wpływu.

Wyjątek powinien mieć miejsce z niewielką szansą, w przeciwnym razie nie są to wyjątki.

zhaorufei
źródło
-1

Musisz pomyśleć o użytkowniku. Awaria aplikacji jest ostatniąrzecz, której chce użytkownik. Dlatego każda operacja, która może się nie powieść, powinna mieć blok try catch na poziomie interfejsu użytkownika. Nie jest konieczne stosowanie try catch w każdej metodzie, ale za każdym razem, gdy użytkownik coś robi, musi być w stanie obsłużyć ogólne wyjątki. To w żaden sposób nie zwalnia Cię od sprawdzania wszystkiego, aby zapobiec wyjątkom w pierwszym przypadku, ale nie ma złożonej aplikacji bez błędów, a system operacyjny może łatwo dodać nieoczekiwane problemy, dlatego musisz przewidzieć nieoczekiwane i upewnić się, czy użytkownik chce z niego skorzystać operacja nie spowoduje utraty danych z powodu awarii aplikacji. Nie ma potrzeby, aby Twoja aplikacja uległa awarii, jeśli wychwycisz wyjątki, nigdy nie będzie ona w stanie nieokreślonym, a awaria ZAWSZE przeszkadza użytkownikowi. Nawet jeśli wyjątek znajduje się na najwyższym poziomie, brak awarii oznacza, że ​​użytkownik może szybko odtworzyć wyjątek lub przynajmniej zapisać komunikat o błędzie, a tym samym znacznie pomóc w rozwiązaniu problemu. Z pewnością dużo więcej niż otrzymanie prostego komunikatu o błędzie, a następnie wyświetlenie tylko okna dialogowego błędu systemu Windows lub czegoś podobnego.

Dlatego NIGDY nie wolno być zarozumiałym i uważać, że aplikacja nie zawiera błędów, co nie jest gwarantowane. I bardzo małym wysiłkiem jest zawinięcie kilku bloków try catch dotyczących odpowiedniego kodu i wyświetlenie komunikatu o błędzie / zarejestrowanie błędu.

Jako użytkownik z pewnością jestem poważnie wkurzony za każdym razem, gdy zawiesza się przeglądarka, aplikacja biurowa lub cokolwiek innego. Jeśli wyjątek jest tak wysoki, że aplikacja nie może kontynuować, lepiej wyświetlić tę wiadomość i powiedzieć użytkownikowi, co ma zrobić (zrestartować, naprawić niektóre ustawienia systemu operacyjnego, zgłosić błąd itp.), Niż po prostu zawiesić się i to wszystko.

Terry Bogard
źródło
Czy możesz spróbować pisać odpowiedzi mniej jak tyrady, a zamiast tego spróbować być bardziej szczegółowymi i spróbować udowodnić swój punkt widzenia? Zobacz też, jak odpowiedzieć .
LuckyLikey