Wyrzucanie wyjątków w metodach

0

Co sądzicie o takiego typu podejściu

public void SomeMethod(SomeClass obj)
	{
		if(obj==null)
			throw new Exception("Message");
		if(obj.prop==true)
			throw new Exception("AnotherMessage");
		//some logic
	}

Czyli wyrzucaniu wyjątków w metodzie. Słyszałem, że nie powinno się ich wyrzucać, gdyż to zmusza programistę, który przejmie kod, do pamiętania o tym aby je obsłużyć. Dla mnie trochę ten argument nie ma sensu, dlatego pytam się was. Dodam że ify sprawdzają poprawność danych (otrzymanych od serwera jsona) i w przypadku gdy są niepoprawne (wchodzą w te instrukcje warunkowe) aplikacja nic nie może zrobić (ich niepoprawność jest krytyczna).
Co o tym sądzicie? Powinienem tak rzucać wyjątkami w metodzie? Może jest inny powód dlaczego tak nie robić?

0

A gdzie można jeszcze wyrzucać wyjątki jak nie w metodzie? Na pewno rzucenie wyjątkiem w sytuacji... wyjątkowej jest lepsze niż zwrócenie nulla czy zignorowanie i udawanie że nic się nie stało. Kod który korzysta z metody musi mieć możliwość rozróżnić sytuację wyjątkową od poprawnej wartości. Wszystko zależy od sytuacji ale najgorsze są biblioteki (a zdarzają się takie) które połykają wszystkie wyjątki w środku i nie mamy żadnej możliwości wykrycia i przekazania userowi z jakiego powodu program nie zadziałał. Nie mamy pańskiego płaszcza i co pan nam zrobi?

Ogólnie jeśli to normalny flow programu, a te "nieprawidłowe" dane są dość częste lub pochodzą od usera to raczej bym był za zwykłą metodą walidującą. Jeśli dane pochodzą z jakiejś aparatury i "złe dane" oznaczają że budynek ze sprzętem prawdopodobnie się pali (a to nie jest oprogramowanie od czujki pożarowej) to można rzucić wyjątkiem. Musisz pamiętać że rzucanie wyjątku to relatywnie kosztowna operacja i nie powinna sterować całkowicie zwykłym przepływem programu.

0

W tym wypadku zakładam, że dane z serwera powinny być za każdym razem poprawne, w razie gdy serwer z jakiegoś powodu zwróci nieprawidłowe dane, chcę w tej metodzie wyrzucić wyjątki.

0

Jaka jest różnica w rzuceniu wyjątkiem, a w zwyczajnym obsłużeniu ifa typu MessageBox albo IActionResult? Jeśli jakiś obiekt jest null to powinien to być wyjątek, czy informacja dla użytkownika - "ej, czegoś nie zaznaczyłeś, nie dodałeś, nie wpisałeś, zrób to jeszcze raz...", ponieważ ty wiesz co przekazać użytkownikowi w momencie gdy obiekt będzie null. Co jest takiego magicznego w wyjątkach? Moim zdaniem nic, a może być tak, że odwróci się to przeciwko tobie. Jeśli zaczniesz wszędzie wciskać wyjątki to skąd będziesz wiedział, który z nich jest twoim niedopatrzeniem (bugiem) w oprogramowaniu? Zakładasz, że nigdy nie zrobisz błędu w kodzie?

2

Jaka jest różnica w rzuceniu wyjątkiem, a w zwyczajnym obsłużeniu ifa typu MessageBox albo IActionResult?

Moim zdaniem taka, że w przypadku danych od usera, spodziewasz się, że może wpisać dane nieprawidłowe(często i gęsto takie przypadki są prawdopodobne) - wtedy bez wyrzucania wyjątku.
Ale w sytuacjach typu błędne dane (które nie powinny mieć miejsca) z zewnętrznego serwera, czy błędna konfiguracja w configu, powinien być wyrzucony wyjątek

0

A to błędna konfiguracja w configu powinna rzucić wyjątkiem i już wtedy nie są to "dane nieprawidłowe", które można obsłużyć w sposób "normalny"? Pytanie tylko, czy to nie jest problem typu X Y? Dla mnie wyjątek to jest coś czego nie przewidziałem, coś co przeoczyłem. Od początku trzeba założyć, że użytkownik to debil i zacznie wklepywać do programu byle co. Według mnie, nie ma na to jednej odpowiedzi jak można, a jak powinno się to robić. Jesteś w stanie walidować dane użytkownika, to jesteś w stanie walidować dane z konfiguracji i wszystkich innych miejsc gdzie mogą być niepoprawne, błędne itp itd. A to co zwrócisz dalej, moim zdaniem, nie ma znaczenia. Znaczenie ma co może z tym zrobić użytkownik, programista, albo nawet sam program.

1

Jak już chcesz używać wyjątków to rób to z głową. Jeśli walidujesz argumenty na początku metody to throw New ArgumentNullException(nameof(obj) ). Albo inny silnie typowany wyjątek, który typem opisuje co się wywaliło (np własny dziedziczący po Exception). Wtedy możesz korzystać z osobnego catch dla każdego typu wyjątku. Message jest wyłącznie dla developera i leci do logów razem ze stack trace i innymi.
Wiadomość o błędzie dla użytkownika wrzucasz do resources i jakoś obslugujesz bo często z perspektywy użytkownika "validation error" jest bez sensu albo mylące.
Przyklad:
Lista api do których wysyłamy requesty:(IP, status, user, password) :

  • catch(ProtocolException e) => sprawdź czy to nie błąd uwierzytelnienia i obsłuż
  • catch(EnpointNotFound e) => ustaw status na offline
    -catch...
    -catch(Exception e) => masz buga, sprawdź, ale nie wysypuj całego programu.
0

Sugeruję zrobić enuma z listą potencjalnych błędów i zwracać odpowiednie kody, rzucanie wyjątków to głupota, bo po pierwsze musisz i tak napisać kod, który obsługuje zwracane wartości z metody, a dodatkowo musisz napisać handler dla wyjątków (no chyba, że zostawiasz je rzucone luzem, co jest jeszcze głupsze), czyli de facto i tak obsługujesz jakąś awaryjną sytuację, tylko na dwa sposoby. Ułatw sobie życie, zrób to raz, do listy enumów szybko dodasz nowe kody błędów, a pisząc dłużej kod docenisz brak stosu handlerów w kodzie wywołującym.

3
Kordoba napisał(a):

Dodam że ify sprawdzają poprawność danych (otrzymanych od serwera jsona) i w przypadku gdy są niepoprawne (wchodzą w te instrukcje warunkowe) aplikacja nic nie może zrobić (ich niepoprawność jest krytyczna).

Proces sprawdzenia poprawności danych wejściowych nazywa się walidacją, a nie rzucaniem wyjątków.

Co o tym sądzicie? Powinienem tak rzucać wyjątkami w metodzie? Może jest inny powód dlaczego tak nie robić?

To, że dane z zewnętrznego serwera mogą być niekompletne jest oczywiste, a wyjątki jak sama nazwa wskazuje nie służą do obsługi sytuacji oczywistych.

Zauważ, że w ramach jednego obiektu wiele różnych właściwości może być błędnych, a przy swoim podejściu z wyjątkami wywalisz się na pierwszym problemie, czyli nie jesteś nawet w stanie na raz zwrócić całej informacji o tym, co jest nie tak z obiektem.

0

@somekind:

przy swoim podejściu z wyjątkami wywalisz się na pierwszym problemie, czyli nie jesteś nawet w stanie na raz zwrócić całej informacji o tym, co jest nie tak z obiektem.

to nie ma nic wspólnego z wyjątkami, równie dobrze mógłby zwrócić new ErrorResult("message") jak i również mógłby rzucić wyjątek po zebraniu rezultatu całej walidacji.

0
WeiXiao napisał(a):

to nie ma nic wspólnego z wyjątkami, równie dobrze mógłby zwrócić new ErrorResult("message") jak i również mógłby rzucić wyjątek po zebraniu rezultatu całej walidacji.

WTF? Autor pokazał kod, to że można napisać inny kod nie zmienia faktu, że pokazał kod, jaki pokazał.

0
somekind napisał(a):

Proces sprawdzenia poprawności danych wejściowych nazywa się walidacją, a nie rzucaniem wyjątków.

Walidacja to pojęcie ogólne, może być w kontekście danych wejściowych od użytkownika, a może być w kontekście stanu modelu, lub danych wyjściowych i tp.
Rzucenie wyjątku lub zwrócenie jakiegoś typu to tylko efekt uboczny nie przejścia walidacji, czyli próby potwierdzenia poprawności jakiegoś stanu.

To, że dane z zewnętrznego serwera mogą być niekompletne jest oczywiste, a wyjątki jak sama nazwa wskazuje nie służą do obsługi sytuacji oczywistych.

Metryka, którą określasz to kiedy powinieneś rzucić wyjątek, nie jest taka oczywista. Równie dobrze możesz zwrócić w sytuacji wyjątkowej Either'a, lecz z drugiej strony języki mieszane jak C# nie mają Algebraic data type, Tagged union czy tam Union type oraz Pattern maching, który z nimi koreluje i pisanie w ten sposób jest zwyczajnie niewygodne.

Zauważ, że w ramach jednego obiektu wiele różnych właściwości może być błędnych, a przy swoim podejściu z wyjątkami wywalisz się na pierwszym problemie, czyli nie jesteś nawet w stanie na raz zwrócić całej informacji o tym, co jest nie tak z obiektem.

Tak, ale tutaj problem występuje na innym poziomie, ludzie nie odróżniają walidacji wprowadzanych danych przez użytkownika, czyli IO od walidacji stanu modelu. Potocznie nazwijmy walidację IO "Walidacją" a walidację stanu modelu "Assercją" Jeśli ktoś obił się o Design By Contract, na pewno będzie mu łatwiej to zrozumieć.

1 użytkowników online, w tym zalogowanych: 0, gości: 1