Obsługa wyjątków

0

Powiedzmy, że mamy zagnieżdżoną metodę (tak to się chyba nazywa? w sensie że np. metoda wywołuje inną metodę która wywołuje inną metodę). I w tej metodzie najniżej wyrzucany jest wyjątek. Powiedzmy, że gdy wystąpi taki wyjątek, chcę wyświetlić komunikat dla użytkownika.

W takim razie czy należy wyrzucać ten wyjątek po kolei do metod wyżej przy użyciu throw? I komunikat wyświetlać w metodzie najwyższej? Czy komunikat wyświetlać w tej metodzie, w której wyrzucany jest wyjątek, a w metodach wyżej mieć try-catche? Czy jakoś inaczej należy zrobić?

Wydaje mi się że pierwszy sposób jest bardziej sensowny, ale słabo czuję temat. Może ktoś zna jakiś artykuł/książkę która by tłumaczyła wyjątki?

0

Ja bym raczej przechwycił wyjątek w komponencie najwyżej w hierarchii i tam zrobił z niego komunikat.

Tak na marginesie w temacie wyjątków, warto wiedzieć że:
Jeśli zakładasz że to będzie częste, to poniekąd jest sterowanie przepływem programu przy użyciu wyjątków - i są dwie skrajne szkoły, które się sprowadzają do:

  1. Nigdy tego nie rób. To jest złe.
  2. Możesz sobie rzucać np BusinessException i potem konwertować na wiadomość dla usera. To jest ok. Spoko.
1

tak to się chyba nazywa?
Nie - nie ma takiego pojęcia jak zagnieżdżona metoda.
W sumie to raczej nikt nie wymyślił specjalnego określenia na taki ciąg wywołania, opis słowny wystarczy.

W takim razie czy należy wyrzucać ten wyjątek po kolei do metod wyżej przy użyciu throw?
Nie - wyjątek zostanie automatycznie przejęty przez najbliższy blok try..catch, niezależnie, jak "daleko" czy głęboko nastąpi rzucenie błędu.
Oczywiście poza przypadkiem, gdy takiego bloku per se nie będzie.

Czy komunikat wyświetlać w tej metodzie, w której wyrzucany jest wyjątek
Nie - to się po prostu nie opłaca, bo w n metodach musiałbyś mieć n niemalże identycznych odwołań do GUI. W razie gdyby nastąpiła chęć zmiany sposobu wyświetlania komunikatu - musiałbyś to zrobić w n metodach, zamiast po prostu w jednym miejscu.

Zresztą zobacz sam:

using System;

public class Test {
	
	public static void Main() {
		try {
			FirstMethod();
			SecondMethod(true);
			ThirdMethod();
		} catch (Exception ex) {
			Console.WriteLine("Wystapil bardzo krytyczny blad: " + ex.Message);
		}
	}
	
	public static void FirstMethod() {
		throw new Exception("FirstMethod() internal error");
	}
	
	public static void SecondMethod(bool pony) {
		if (pony) {
			throw new Exception("SecondMethod() internal error, case 1");
		} else {
			throw new Exception("SecondMethod() internal error, case 2");
		}
	}
	
	public static void ThirdMethod() {
		int x = 0;
		
		for (int i = 0; i < 10; i++) {
			x += i & 1;
		}
		
		if (x%2 == 0) {
			throw new Exception("ThirdMethod() internal error");
		}
	}
}

Oraz:

using System;
 
public class Test {
 
	public static void Main() {
		try {
			FirstMethod();
			SecondMethod(true);
			ThirdMethod();
		} catch (Exception ex) {
		}
	}
 
	public static void FirstMethod() {
		Console.WriteLine("Wystapil bardzo krytyczny blad: FirstMethod() internal error");
		throw new Exception();
	}
 
	public static void SecondMethod(bool pony) {
		if (pony) {
			Console.WriteLine("Wystapil bardzo krytyczny blad: SecondMethod() internal error, case 1");
			throw new Exception();
		} else {
			Console.WriteLine("Wystapil bardzo krytyczny blad: SecondMethod() internal error, case 2");
			throw new Exception();
		}
	}
 
	public static void ThirdMethod() {
		int x = 0;
 
		for (int i = 0; i < 10; i++) {
			x += i & 1;
		}
 
		if (x%2 == 0) {
			Console.WriteLine("Wystapil bardzo krytyczny blad: ThirdMethod() internal error");
			throw new Exception();
		}
	}
}

A teraz powiedzmy, że chcesz zmienić treść komunikatu błędu - ile razy dłużej zajmie Ci zmiana w wersji drugiej?

Wydaje mi się że pierwszy sposób jest bardziej sensowny, ale słabo czuję temat

Kurczę - na logikę: co jest bardziej sensownego w robieniu kopiuj-wklej tego samego kodu do wyświetlania wiadomości użytkownikowi i rzucania wyjątku tak czy siak (bo inaczej nie przerwiesz wykonywania kodu), zamiast rzucenia wyjątku i obsługi go w innym, przeznaczonym do tego celu miejscu aplikacji?
Powiedz mi proszę, bo jestem ciekaw, jakie miałbyś argumenty za tym (ponieważ zakładam, że nie rzuciłeś sobie hasełka od tak, tylko jakiś proces myślowy przed napisaniem posta przeprowadziłeś i jestem ciekaw jego rezultatów).

0
Patryk27 napisał(a):

Kurczę - na logikę: co jest bardziej sensownego w robieniu kopiuj-wklej tego samego kodu do wyświetlania wiadomości użytkownikowi i rzucania wyjątku tak czy siak (bo inaczej nie przerwiesz wykonywania kodu), zamiast rzucenia wyjątku i obsługi go w innym, przeznaczonym do tego celu miejscu aplikacji?
Powiedz mi proszę, bo jestem ciekaw, jakie miałbyś argumenty za tym (ponieważ zakładam, że nie rzuciłeś sobie hasełka od tak, tylko jakiś proces myślowy przed napisaniem posta przeprowadziłeś i jestem ciekaw jego rezultatów).

Żadnego kopiuj-wklej by nie było, 1 raz wyświetlanie komunikatu a wyżej try-catche. Nie będę bronić tego rozwiązania bo jest złe, to tylko były jakieś tam propozycje żeby było widać że coś kombinuję a nie proszę o rozwiązanie na tacy :) Próbuję zrozumieć temat bo mam problem z wyjątkami, więc dzięki za odpowiedź.

W takim razie czy należy wyrzucać ten wyjątek po kolei do metod wyżej przy użyciu throw?

Nie - wyjątek zostanie automatycznie przejęty przez najbliższy blok try..catch, niezależnie, jak "daleko" czy głęboko nastąpi rzucenie błędu.
Oczywiście poza przypadkiem, gdy takiego bloku per se nie będzie.

Nie wiem czy dobrze rozumiem - chodzi o to że w metodzie najniżej użyć throw, w metodach "pośrednich" nie obsługiwać wyjątku, a w metodzie "najwyżej", w której chcę wyświetlić komunikat, użyć try-catch?

0

Nie wiem czy dobrze rozumiem - chodzi o to że w metodzie najniżej użyć throw, w metodach "pośrednich" nie obsługiwać wyjątku, a w metodzie "najwyżej", w której chcę wyświetlić komunikat, użyć try-catch?
Tak, dokładnie ;-)

0

Prosta zasada: wyjątki obsługujesz tam, gdzie wiesz co z nimi zrobić i co najważniejsze: obsługujesz konkretne ich typy a Exception łapiesz w ostateczności. W Twoim przypadku w punkcie startowym aplikacji łapiesz wszystkie niezłapane wyjątki i wyrzucasz komunikat z błędem. Inny przykład na pseudokodzie:

 

void PrzeczytajPlik()
{
      try
     {
            OpenFile();
     }
     catch(FileNotFound ex)
     {
            ModifyPathAndOpenFile();
     }
     catch(Exception ex)
     {
           throw; // nie wiemy jak to obsłużyć, rzucamy dalej
     }
}

Jeżeli nie znalazł pliku to próbujemy naprawić ten błąd modyfikując jakoś ścieżkę na jakąś alternatywną. Jeżeli rzuca nam inny błąd (np. null reference exception) to nie wiemy co z nim zrobić i wyrzucamy wyjątek wyżej (być może metoda wyżej potrafi obsłużyć nulla ale to nas nie obchodzi).

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