Mamy aplikację WPF, której części mogą generować wyjątki w czasie wykonywania. Chciałbym globalnie złapać każdy nieobsługiwany wyjątek i zapisać je, ale poza tym kontynuować wykonywanie programu tak, jakby nic się nie wydarzyło (trochę jak VB On Error Resume Next
).
Czy jest to możliwe w C #? A jeśli tak, to gdzie dokładnie powinienem umieścić kod obsługi wyjątków?
Obecnie nie widzę żadnego punktu, w którym mógłbym zawinąć try
/ catch
dookoła i który wychwyciłby wszystkie możliwe wyjątki. I nawet wtedy zostawiłbym wszystko, co zostało stracone z powodu połowu. A może myślę tutaj w strasznie złych kierunkach?
ETA: Ponieważ wiele osób poniżej zwróciło na to uwagę: Aplikacja nie służy do kontrolowania elektrowni jądrowych. Jeśli się zawiesi, to nie jest to wielka sprawa, ale przypadkowe wyjątki, które są głównie związane z interfejsem użytkownika, są uciążliwe w kontekście, w którym zostaną użyte. Było ich kilka (i prawdopodobnie nadal), a ponieważ wykorzystuje ona architekturę wtyczek i może być rozszerzana przez innych (w tym przypadku także studentów), więc nie ma doświadczonych programistów, którzy byliby w stanie napisać całkowicie bezbłędny kod).
Jeśli chodzi o wyjątki, które zostaną złapane: rejestruję je w pliku dziennika, łącznie z kompletnym śledzeniem stosu. To był sedno tego ćwiczenia. Żeby po prostu przeciwstawić się tym, którzy zbyt dosłownie przyjęli moją analogię do OERN VB.
Wiem, że ślepe ignorowanie niektórych klas błędów jest niebezpieczne i może uszkodzić moją instancję aplikacji. Jak powiedziano wcześniej, ten program nie jest kluczowy dla nikogo. Nikt przy zdrowych zmysłach nie postawiłby na to przetrwanie ludzkiej cywilizacji. To po prostu małe narzędzie do testowania określonych podejść projektowych wrt. Inżynieria oprogramowania.
Do natychmiastowego użycia aplikacji nie ma wielu rzeczy, które mogą się zdarzyć na wyjątku:
- Bez obsługi wyjątków - okno dialogowe błędu i wyjście z aplikacji. Eksperyment należy powtórzyć, choć prawdopodobnie z innym tematem. Żadne błędy nie zostały zarejestrowane, co jest niefortunne.
- Ogólna obsługa wyjątków - łagodny błąd w pułapce, bez szkody. To powinien być powszechny przypadek oceniany na podstawie wszystkich błędów, które widzieliśmy podczas programowania. Ignorowanie tego rodzaju błędów nie powinno mieć bezpośrednich konsekwencji; podstawowe struktury danych są testowane wystarczająco dobrze, aby z łatwością to przetrwały.
- Obsługa wyjątków ogólnych - poważny błąd w pułapce, prawdopodobnie awaria w późniejszym momencie. Może się to zdarzyć rzadko. Do tej pory nigdy tego nie widzieliśmy. Błąd i tak jest rejestrowany, a awaria może być nieunikniona. Jest to więc koncepcyjnie podobne do pierwszego przypadku. Tyle że mamy ślad stosu. W większości przypadków użytkownik nawet tego nie zauważy.
Jeśli chodzi o dane eksperymentu generowane przez program: poważny błąd w najgorszym przypadku po prostu nie spowodowałby zapisu danych. Subtelne zmiany, które zmieniają nieznacznie wynik eksperymentu, są raczej mało prawdopodobne. I nawet w takim przypadku, jeśli wyniki wydają się wątpliwe, błąd został zarejestrowany; nadal można wyrzucić ten punkt danych, jeśli jest on całkowitą wartością odstającą.
Podsumowując: Tak, uważam się za przynajmniej częściowo zdrowego rozsądku i nie uważam globalnej procedury obsługi wyjątków, która pozostawia działający program za koniecznie całkowicie zły. Jak już wspomniano dwa razy, taka decyzja może być ważna, w zależności od wniosku. W tym przypadku została uznana za ważną decyzję, a nie całkowitą i całkowitą bzdurę. W przypadku każdej innej aplikacji ta decyzja może wyglądać inaczej. Ale proszę nie oskarżaj mnie ani innych ludzi, którzy pracowali nad tym projektem, aby potencjalnie wysadzili świat tylko dlatego, że ignorujemy błędy.
Uwaga dodatkowa: dla tej aplikacji jest dokładnie jeden użytkownik. Nie jest to coś takiego jak Windows czy Office, z którego korzystają miliony, gdzie koszt bańki wyjątków dla użytkownika byłby już zupełnie inny.
On Error Resume Next
nie jest możliwy w języku C #. PoException
(C # nie ma „błędów”) nie można po prostu wznowić z następną instrukcją: wykonywanie będzie kontynuowane wcatch
bloku - lub w jednej z procedur obsługi zdarzeń opisanych w odpowiedziach poniżej.Odpowiedzi:
Użyj
Application.DispatcherUnhandledException Event
. Podsumuj to pytanie (patrz odpowiedź Drew Noakesa ).Pamiętaj, że nadal będą wyjątki, które uniemożliwiają pomyślne wznowienie działania aplikacji, na przykład po przepełnieniu stosu, wyczerpaniu pamięci lub utracie połączenia z siecią podczas próby zapisania w bazie danych.
źródło
Przykładowy kod wykorzystujący NLog, który będzie przechwytywał wyjątki zgłaszane ze wszystkich wątków w AppDomain , z wątku dyspozytora interfejsu użytkownika i funkcji asynchronicznych :
App.xaml.cs:
źródło
UnhandledException
. Musiałem spojrzeć na Windows Event Log Viewer, aby dowiedzieć się, co się dzieje ...e.Handled = true;
uUnhandledException
, że aplikacja nie będzie katastrofy na Wyjątki UIAppDomain.UnhandledException Event
źródło
Oprócz tego, co wspomnieli tu inni, zauważ, że łączenie
Application.DispatcherUnhandledException
(i jego podobnych ) zw
app.config
będzie zapobiec wtórnej nici wyjątek od zamykania aplikacji.źródło
Oto pełny przykład użycia
NLog
źródło
Jak „Wznów błędu na VB dalej?” To brzmi trochę przerażająco. Pierwsza rekomendacja to nie rób tego. Drugie zalecenie to nie rób tego i nie myśl o tym. Musisz lepiej odizolować swoje usterki. Sposób podejścia do tego problemu zależy od struktury kodu. Jeśli używasz wzoru takiego jak MVC lub podobny, nie powinno to być zbyt trudne i zdecydowanie nie wymagałoby globalnego połykania wyjątków. Po drugie, poszukaj dobrej biblioteki rejestrowania, takiej jak log4net lub użyj śledzenia. Musielibyśmy wiedzieć więcej szczegółów, takich jak o jakich wyjątkach mówisz i jakie części Twojej aplikacji mogą powodować zgłaszanie wyjątków.
źródło