CodeGym /Kursy /C# SELF /Wprowadzenie do wyjątków i ich hierarchii

Wprowadzenie do wyjątków i ich hierarchii

C# SELF
Poziom 13, Lekcja 0
Dostępny

1. Wstęp

Wyobraź sobie, że piszesz kalkulator do dzielenia dwóch liczb. Wszystko działa super, dopóki ktoś nie spróbuje podzielić przez zero:

int a = 10;
int b = 0;
int result = a / b; // Bum!
Dzielenie przez zero powoduje wyjątek

W tym momencie program się "wywala", a użytkownik widzi straszny komunikat o błędzie. To właśnie wyjątkowa sytuacja — zdarzenie, które nie powinno mieć miejsca w "normalnym" scenariuszu działania programu i wymaga specjalnej uwagi.

Wyjątek — to specjalny mechanizm, dzięki któremu .NET informuje twój program, że wydarzyło się coś nieoczekiwanego i wykonanie powinno zostać przerwane albo obsłużone w specjalny sposób.

Kiedy pojawia się błąd wykonania (np. dzielenie przez zero, próba dostępu do nieistniejącego pliku, albo — stary znajomy — dereferencja null), .NET "rzuca" (throw) specjalny obiekt-wyjątek. To prowadzi do szukania handlera, który potrafi "złapać" (catch) sytuację i wie, jak zareagować.

Dlaczego nie zwracać "kodu błędu"?

Można by zwracać kod błędu — i wiele starożytnych języków (Pascal, C, a nawet niektóre współczesne API) tak robi. Ale to niewygodne i niebezpieczne: łatwo zapomnieć sprawdzić kod błędu (wszyscy liczymy na najlepsze) — i bardzo trudno zrozumieć, gdzie dokładnie coś poszło nie tak. Wyjątki pozwalają centralnie śledzić wszelkie błędy i reagować na nie elastycznie, nie zaśmiecając głównego kodu masą ifów.

2. "Rzucanie" wyjątku

Wyjątki mogą pojawić się automatycznie — przy błędzie środowiska wykonawczego, albo być rzucone ręcznie za pomocą słowa kluczowego throw:


int[] arr = new int[2];
arr[10] = 5; // wyjątek poleci sam System.IndexOutOfRangeException

throw new Exception("Absolutna katastrofa!"); // ręcznie rzucamy wyjątek Exception

Nawet jeśli wydaje ci się, że twój program jest idealnie zaprojektowany, zawsze może się wydarzyć coś niespodziewanego: użytkownik zamknął plik, internet padł, ktoś wyłączył zasilanie komputera (no prawie).

Na szczęście .NET dał nam nie tylko mechanizm "rzucania" wyjątków, ale też narzędzia do ich łapania i obsługi — tym zajmiemy się za chwilę.

3. Cykl życia wyjątku: od throw do catch

Kiedy w kodzie dzieje się coś nieprzyjemnego, .NET uruchamia "awaryjną procedurę":

  1. Tworzy obiekt wyjątku (np. IndexOutOfRangeException).
  2. Rzuca go za pomocą słowa kluczowego throw.
  3. Szukaj handlera: przegląda stos wywołań od dołu do góry (od bieżącej metody do wywołującej) — szuka pierwszego bloku catch, który pasuje do typu rzuconego wyjątku.
  4. Jeśli znajdzie handler — program kontynuuje wykonanie wewnątrz bloku catch.
  5. Jeśli nie znajdzie żadnego handlera — program kończy się awaryjnie i wyświetla "stos wywołań" z detalami błędu.

Wygląda to jak napięty lot piłki po schodach — dopóki nie trafi na odbiorcę, może długo "skakać" po stosie.

4. Hierarchia wyjątków w .NET

Drzewo "ojców i dzieci"

W .NET (jak w większości języków OOP) wyjątki są zrobione jako klasy, które dziedziczą po sobie i tworzą całą hierarchię.

Wszystkie mają wspólnego przodka — bazową klasę System.Exception.


System.Object
    └─ System.Exception
         ├─ System.SystemException
         │     ├─ System.NullReferenceException
         │     ├─ System.IndexOutOfRangeException
         │     ├─ System.DivideByZeroException
         │     ├─ System.OutOfMemoryException
         │     └─ ... i wiele innych
         ├─ System.IO.IOException
         │     ├─ System.IO.FileNotFoundException
         │     ├─ System.IO.DirectoryNotFoundException
         │     └─ ...
         ├─ System.ArgumentException
         │     ├─ System.ArgumentNullException
         │     └─ System.ArgumentOutOfRangeException
         └─ (twoje własne Exception-klasy)
Schematyczna hierarchia wyjątków w .NET

Dlaczego klasy?

Dzięki hierarchii klas możesz złapać od razu całą "klasę" problemów — na przykład wszystkie błędy związane z argumentami funkcji (ArgumentException i jego potomkowie). Co więcej, możesz dodawać własne typy błędów (o tym — na kolejnych wykładach).

Najpopularniejsze wyjątki .NET

  • NullReferenceException — próba dostępu do metody lub właściwości obiektu, który jest null. Stary znajomy!
  • DivideByZeroException — dzielenie przez zero.
  • IndexOutOfRangeException — wyjście poza granice tablicy.
  • ArgumentException, ArgumentNullException, ArgumentOutOfRangeException — błędne parametry metod.
  • FileNotFoundException, IOException — problemy przy pracy z plikami.
  • InvalidOperationException — operacja niemożliwa w bieżącym stanie obiektu.
  • FormatException — nieprawidłowy format danych (np. próba konwersji "abcd" na liczbę).

5. Przykłady: jak "wystrzeliwują" różne wyjątki

Zobaczmy dla jasności przykłady kodu, które powodują różne wyjątki.

Przykład 1: NullReferenceException

string? str = null;
Console.WriteLine(str.Length); // Tutaj "Bum!" — str jest null

Wynik:

Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.

Przykład 2: DivideByZeroException

int a = 42;
int b = 0;
int c = a / b; // Niebezpieczne! Dzielenie przez 0

Wynik:

Unhandled exception. System.DivideByZeroException: Attempted to divide by zero.

Przykład 3: IndexOutOfRangeException

int[] numbers = { 1, 2, 3 };
Console.WriteLine(numbers[5]); // Nie ma elementu o indeksie 5

Tu ewidentnie są za duże indeksy, a wynik to:

Unhandled exception. System.IndexOutOfRangeException: Index was outside the bounds of the array.

Przykład 4: FileNotFoundException

using System.IO;

string content = File.ReadAllText("secret.txt");

Jeśli nie masz pliku o nazwie "secret.txt", dostaniesz mniej więcej taki komunikat:

Unhandled exception. System.IO.FileNotFoundException: Could not find file '/Users/zapp/RiderProjects/ConsoleApp1/ConsoleApp1/bin/Debug/net9.0/secret.txt'.

Przykład 5: FormatException

string input = "trzynascie";
int number = int.Parse(input); // String nie jest liczbą

Wynik:

Unhandled exception. System.FormatException: The input string 'trzynascie' was not in a correct format.

6. Jak wykorzystać tę wiedzę?

Zrozumienie, jak działają wyjątki, jest naprawdę ważne dla każdego programisty. To nie tylko "teoria dla teorii", ale praktyczna umiejętność, która bezpośrednio wpływa na stabilność twoich programów. Kiedy wiesz, jak poprawnie obsługiwać błędy, twój program nie będzie się "wywalał" przy pierwszym lepszym problemie, tylko spokojnie i jasno powie użytkownikowi, co poszło nie tak. To czyni go bardziej niezawodnym, profesjonalnym i po prostu przyjaźniejszym dla ludzi.

I to nie tylko kwestia wygody. Na rozmowach kwalifikacyjnych często pytają o mechanikę obsługi wyjątków, typy Exception i jak w ogóle działa ten mechanizm w .NET. Więc dobre zrozumienie tematu — to też plus do karmy przy szukaniu pracy.

Poza tym, jeszcze nie raz spotkasz się z wyjątkami w prawdziwych projektach. Praca z plikami, siecią, bazami danych, zewnętrznymi bibliotekami i frameworkami — wszystko to mocno korzysta z systemu wyjątków. Dlatego lepiej od razu ogarnąć, jak to działa, żeby potem nie było niespodzianek.

7. Typowe błędy przy pracy z wyjątkami

Błąd nr 1: ignorowanie wyjątków jako takich.
Niektórzy początkujący (a czasem i doświadczeni programiści) traktują wyjątki jak coś szkodliwego albo przeszkadzającego. Albo je całkiem ignorują, albo — co gorsza — opakowują kod w catch { } i nic nie robią. W efekcie program "po cichu" działa dalej w dziwnym stanie i nie da się dojść, dlaczego coś się wywaliło.

Błąd nr 2: mylenie wyjątków ze zwykłymi błędami.
Często zapomina się, że nie każdy błąd trzeba łapać przez try-catch. Na przykład, jeśli użytkownik wpisał złe dane, lepiej sprawdzić je ręcznie, a nie liczyć na FormatException i tym bardziej nie używać wyjątków jako mechanizmu logiki. Wyjątki są od wyjątkowych przypadków, a nie od rutyny.

Błąd nr 3: złe rozumienie hierarchii wyjątków.
Czasem ktoś próbuje łapać zbyt ogólną klasę (Exception) i łapie wszystko, nawet te błędy, których lepiej nie ruszać. A czasem odwrotnie — łapie zbyt wąskie typy (IndexOutOfRangeException, NullReferenceException), zapominając, że mogą się pojawić też inne. Ważne jest, żeby rozumieć, jak działa hierarchia wyjątków w .NET i co dokładnie chcesz obsłużyć.

I najważniejsze — pamiętaj: wyjątki w C# to nie awaria i nie sygnał "wszystko stracone", tylko po prostu mechanizm przełączania na specjalny scenariusz wykonania. To potężne narzędzie, jeśli używasz go z głową.

2
Zadanie
C# SELF, poziom 13, lekcja 0
Niedostępne
Prosta demonstracja wyrzucenia wyjątku
Prosta demonstracja wyrzucenia wyjątku
2
Zadanie
C# SELF, poziom 13, lekcja 0
Niedostępne
Różne popularne wyjątki
Różne popularne wyjątki
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION