9. Výjimky

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.

9.1. Hlídaný blok (try)

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.

[ukázka kódu]
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.

[ukázka kódu]
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(...)

[ukázka kódu]
...
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.

9.2. Blok obsluhy (catch)

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í:

[ukázka kódu]
...
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) {};

9.3. Koncový blok (finally)

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.

[ukázka kódu]
...
public stativ void Main(){
   try {
      Console.WriteLine(MatematickeOperace.vydel(3,0));
   }
   catch (DivideByZeroException e) { e.Message; }
   finally { 
     Console.WriteLine("koncovy blok"); 
   }
...

9.4. Výjímky definované v .NET

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

ExceptionZákladní třída pro všechny výjimky.
SystemExceptionZákladní třída pro všechny druhy výjimek generovaných za běhu aplikace.
IndexOutOfRangeExceptionPřístup k prvku mimi rozsah pole.
NullReferenceExceptionGenerovaná při pokusu pracovat s neinicializovanou referencí.
ArgumentExceptionZákladní třída pro všechny výjimky způsobené chybnými argumenty.
ArgumentNullExceptionParametr s null hodnotou nebyl očekáván.
InteropExceptionVý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í.