Wyjątki w C#
Opracował dr Robert Fidytek
2
Wyjątki
Nie ma programu, który nie byłby pozbawiony błędów. Są jedynie programy,
w których błędy się nie ujawniają, co jednak nie oznacza, iż program nie
zawiera błędów. Występują one w sytuacjach, o których nie pomyślał
programista. Sytuacje, które mogą spowodować błąd można podzielić na
trzy kategorie:
●
Błędy programisty – błędy popełniane najczęściej przez nieuwagę
programisty np: wykroczenie indeksu tablicy poza jej zakres.
●
Błędy użytkownika - błędy spowodowane niewłaściwym użytkowaniem
programu przez użytkownika np: wpisanie liter w miejsce kodu
pocztowego. Jeśli w kodzie programu programista nie zadba o
sprawdzanie poprawności wprowadzanych danych może nastąpić
wygenerowanie błędu.
●
Wyjątki - anomalie uruchomieniowe, które trudno przewidzieć w czasie
pisania programu np: próba łączenia się z bazą danych, która już nie
istnieje.
3
Do wyłapywania wyjątków służy blok try. W tym bloku umieszcza się
instrukcje kodu, które mogą spowodować pojawienie się wyjątku.
Natomiast do wyłapywania pojawiających się błędów służy blok catch.
W bloku catch umieszcza się kod, który informuje użytkownika w
przyjazny sposób o tym, że wystąpił jakiś błąd. Dzięki wyłapywaniu
pojawiających się błędów program nie zawiesza nagle swojego
działania. Oprócz kodu informującego w tym bloku umieszcza się
instrukcje, które obsługują błąd np: wycofują wprowadzone zmiany.
Schemat obsługi wyjątków:
try
{
//"pilnowany" kod programu
}
catch
(TypWyjątku ex)
//ex – uchwyt do zgłoszonego wyjątki
{
//kod obsługi wyjątku
}
Blok try i catch
4
Jeżeli podczas wykonywania bloku try (kodu "pilnowanego") nie zostanie
zgłoszony wyjątek, to blok catch (kod obsługi wyjątku) zostanie pominięty.
W przypadku, gdy podczas wykonywania zostanie zgłoszony wyjątek typu
podanego w instrukcji catch lub typu, dla którego typ podany w instrukcji
catch jest typem ogólnym (bazowym), wtedy wykonanie kodu
"pilnowanego“ zostanie przerwane i przechodzimy do wykonania kodu
obsługi wyjątku.
Po wykonaniu wszystkich instrukcji kodu obsługi wyjątku program
przechodzi do wykonania instrukcji znajdujących się za blokiem catch,
oczywiście pod warunkiem, że w kodzie obsługi wyjątku nie został
zgłoszony wyjątek.
Jeżeli nie zostanie znaleziony blok try, z którym skojarzona jest instrukcja
catch (z odpowiednim typem wyjątku), program zostanie przerwany i
zostanie wyświetlony komunikat o kłopotach z danym programem.
Obsługa wyjątków
5
Jeżeli chcemy przechwycić wszystkie zgłoszone wyjątki w danym bloku try,
w instrukcji catch nie podajemy typu wyjątku:
try
{
//"pilnowany" kod programu
}
catch
{
//kod obsługi wyjątku
}
Rozwiązanie to uniemożliwia jednak uzyskanie dostępu do obiektu wyjątku,
który może zawierać ważne informacje na temat błędu.
try
{
//"pilnowany" kod programu
}
catch
(
System.Exception ex
)
//uzyskujemy dostęp do informacji o błędzie
{
//kod obsługi wyjątku
}
Obsługa wszystkich wyjątków
6
Przykład 1: dzielenie przez zero
static
void
Main(
string
[] args)
{
int
a = 0, b;
try
{
b = 1 / a;
//wyjątek (dzielimy przez zero)
}
catch
(
DivideByZeroException
ex)
{
Console
.WriteLine(
"Próbujesz dzielić przez zero!"
);
}
Console
.ReadKey(
true
);
}
7
Przykład 2: dzielenie przez zero
static
void
Main(
string
[] args)
{
int
a = 0, b;
try
{
b = 1 / a;
//wyjątek (dzielimy przez zero)
}
catch
(
System.Exception
ex)
{
Console
.WriteLine(
"Komunikat wyjątku {0}"
,ex.Message);
}
Console
.ReadKey(
true
);
}
8
Z pojedynczym blokiem try może zostać skojarzonych wiele bloków catch.
Zgłoszony wyjątek może być obsłużony tylko przez jeden blok catch.
Wyjątek zostanie obsłużony przez pierwszy blok catch, którego typ jest
zgodny z typem zgłoszonego wyjątku.
Dlatego powinno się umieszczać
wyjątki bardziej szczegółowe przed wyjątkami bardziej ogólnymi. W
przeciwnym razie wyjątek bardziej szczegółowy nigdy nie zostałby
wykonany.
try
{
//"pilnowany" kod programu
}
catch
(
DivideByZeroException
ex)
{
//kod obsługi wyjątku szczegółowego
}
catch
(
System.Exception ex
)
{
//kod obsługi wyjątku ogólnego
}
Użycie wielu bloków catch
9
W sytuacji pojawienia się wyjątku jest przerywane działanie instrukcji w
bloku try, a sterowanie jest przenoszone do catch. Mechanizm wyjątków
udostępnia jeszcze jeden blok - jest to finally. Jest on opcjonalny, a
instrukcje w nim zawarte są realizowane zawsze na końcu, niezależnie czy
wystąpił wyjątek czy nie. Blok ten może zapobiegać duplikowaniu kodu,
który musiałby znajdować się blokach try i catch. Przykładowe sytuacje, w
jakich powinno się używać się tego bloku to między innymi: zamykanie
plików, rozłączanie z bazą danych.
try
{
//"pilnowany" kod programu
}
catch
(
TypWyjątku
ex)
{
//kod obsługi wyjątku
}
finally
{
//kod realizowany na końcu, niezależnie od wystąpienia wyjątku
}
Blok finally
10
Wyjątek można zgłosić samodzielnie, służy do tego instrukacja throw:
throw
new
TypWyjątku();
Z wyjątkiem możemy skojarzyć pewien komunikat informujący o błędzie:
throw
new
TypWyjątku(
"Treść komunikatu"
);
W razie konieczności możemy też ponownie zgłosić wyjątek:
try
{
//"pilnowany" kod programu
}
catch
(Exception ex)
{
//kod obsługi wyjątku
throw;
//ponowne zgłoszenie wyjątku
}
Zgłaszanie wyjątków
11
Przykład
double
a = 1, b;
try
{
Console
.Write(
"Podaj liczbę: "
);
b =
Convert
.ToDouble(
Console
.ReadLine());
if
(b == 0)
throw
new
DivideByZeroException
(
"Dzielenie przez zero"
);
else
a = a / b;
}
catch
(
DivideByZeroException
ex)
{
Console
.WriteLine(
"Komunikat: {0}"
, ex.Message);
}
catch
(
FormatException
ex)
{
Console
.WriteLine(
"Nie udało się przekonwertować napisu na liczbę"
);
}
finally
{
Console
.WriteLine(
"Blok finally"
);
}
Console
.ReadKey(
true
);
Przetestuj program dla
wartości: 12, 0, ALA.
12
Typy wyjątków