Pokud program narazí na neočekávaný problém, například snažíme-li se zapsat hodnotu do pole na index, který pro toto pole není definován, objeví se výjimka. Výjimky můžeme chápat jednak jako takovýto problém a jednak jako objekty nesoucí informaci a vzniklém problému.
Výjimky jako objekty jsou odvozeny ze třídy Object. Z této třídy je odvozena základní třída výjimek Exception, ze které ostatní třídy výjimek dědí.
Výjimky může vyvolat buď prostředí .Net Framework. Jedná se například o dělení nulou, pokus o vstup mimo hranice pole apod. Můžeme je můžeme vyvolat také sami pomocí příkazu throw.
Pokud chceme ošetřit - hlídat vznik výjimky, provedeme příkazy, které by mohly výjimku vyvolat, v hlídaném bloku. Strukturu výjimky ukazuje následující příklad.
try { … } catch (System.FileException e) { … } catch (System.Exception e) { … } finally { … } |
Vezměme například metodu, kterou jsme použili v části 3.3.6 - dělení nulou.
class MatematickeOperace { ... static double vydel(double delenec, double delitel) { if(delitel == 0) throw new DivideByZeroException("Nulou nelze delit!"); else return(delenec / delitel); } public static void Main() { // zde vznikne vyjimka, kterou chceme osetrit Console.WriteLine(MatematickeOperace.vydel(3,9)); } } |
Hlídaný blok začíná klíčovým slovem try a pokračuje samotným blokem. V našem případě budeme hlídat použití statické metody MatematickeOperace.vydel(...)
... public static void Main() { // deleni uvedeme do hlidaneho bloku try { Console.WriteLine(MatematickeOperace.vydel(3,0); } ... } |
Hlídaný blok nám sice ohlídá vznik výjimky, ale sám o sobě nemá valnou cenu. Musí být použit ve spojení s dalšími bloky - catch a (nebo) finally.
Blok obsluhy se provádí ve spojení s blokem try tehdy, pokud v bloku try dojde ke vzniku výjimky. Předchozí ukázku rozšíříme o blok catch. Jelikož nám hrozí dělení nulou, budeme hlídat výskyt výjimky DivideByZeroException. Můžeme použít také nadřazenou obecnou výjimku ArithmeticException nebo Exception, ze které obě třídy výjimek dědí:
... public static void Main() { // deleni uvedeme do hlidaneho bloku try { Console.WriteLine(MatematickeOperace.vydel(3,0); } catch (DivideByZeroException e) { e.Message; } } ... |
Pokud víme o více výjimkách, které se mohou v hlídaném bloku objevit, jednoduše přidáme další blok obsluhy.
Výjimky obsahují mimo jiné užitečnou vlastnost Message. Ta umožňuje přístup k chybovému hlášení, které se dá zobrazit v případě výskytu výjimky.
Výjimku lze také pouze zachytit bez dalšího zpracování. Potom stačí v bloku catch uvést pouze catch (Exception) {};
Někdy se nám může stát, že pracujeme v hlídaném bloku a zde se vyskytne výjimka. My budeme chtít, aby se v každém případě - tj. po vzniku výjimky i tehdy, když nevznikne, vykonala určitá část kódu související s hlídaným blokem.
Mějme například soubor, který otevřeme a poté do něj v hlídaném bloku zapisujeme data. Pokud se při zápisu dat vyskytne výjimka, přejde se na blok obsluhy a soubor by mohlzůstat nadále otevřen. Proto můžeme použít koncový blok, který způsobí zavření souboru v každém případě - tedy pokud se výjimka objeví i pokud ne.
... public stativ void Main(){ try { Console.WriteLine(MatematickeOperace.vydel(3,0)); } catch (DivideByZeroException e) { e.Message; } finally { Console.WriteLine("koncovy blok"); } ... |
Knihovna tříd .NET Framework definuje celou sadu výjimek. Některé z nich uvádí následující tabulka.
Tabulka 4.3. Tabulka některých výjimek z knihoven :NET Framework
Exception | Základní třída pro všechny výjimky. |
SystemException | Základní třída pro všechny druhy výjimek generovaných za běhu aplikace. |
IndexOutOfRangeException | Přístup k prvku mimi rozsah pole. |
NullReferenceException | Generovaná při pokusu pracovat s neinicializovanou referencí. |
ArgumentException | Základní třída pro všechny výjimky způsobené chybnými argumenty. |
ArgumentNullException | Parametr s null hodnotou nebyl očekáván. |
InteropException | Výjimka generovaná mimi CLR .NET Framework. |
V prostředí .NET můžeme definovat vlastní typy vyjímek. Všechny vycházejí ze třídy System.Exception. Možnosti, které při vytváření vlastního typu výjimky máme, demonstrují konstruktory třídy Exception.
public Exception();
Implicitní konstruktor inicializuje členská data na předdefinované hodnoty.
public Exception(string)
Nastavuje popis výjimky jako textový řetězec.
public Exception(SerializationInfo, StreamingContext)
Inicializuje člena třídy tzv. serializovanými daty.
public Exception(string, Exception)
Dává nám možnost vytvořit událost obsahující data jiné události. Takto můžeme tvořit celou hierarchii do sebe zanořených událostí.