Poznáváme C# a Microsoft.NET 14. díl – výjimky po druhé

V dnešním díle si rozšíříme znalosti o tématu, které jsem načal v předchozím díle, což byl systém výjimek v prostředí MS .NET framework. Mimo jiné se můžete těšit na seznámení s tvorbou vlastních typů výjimek.

Předávání výjimek

Systém předávání (propagace) výjimek umožňuje nezachycovat výjimku ihned při jejím vyhození volanou metodou. Tedy metoda ve které se výjimka vyskytla vlastně ponechává odpovědnost na volajících metodách. Vzniklá výjimka bude „probublávat“ výše v hierarchii volaných metod dokud nedojde k jejímu zachycení. Pokud výjimka námi není nikde v hierarchii zachycena, je zachycena běhovým prostředím a uživateli se zobrazí okno s hlášení o vzniklé výjimce. Následující příklad demonstruje jak je možné předávat výjimky.

Poznámka: To, že se při nezpracované výjimce zobrazí okno .NET frameworku s popisem výjimky je nejběžnější reakce, ale není jediná možná. Co bude provedeno při výskytu nezpracované výjimky je možné ovlivnit.

public class DeleniNulou
{
 public static float Vydel(int a,int b)
 {
  if (b == 0)
   //vyhozeni vyjimky
   throw new DivideByZeroException();
  return a / b;
 }

public static void MetodaVolajiciVydel()
 {
  //dojde k vyhozeni vyjimky
  //ktera bude predana volajici metode
  float lVysledek = Vydel(4,0);
  Console.WriteLine("Vysledek deleni: " + lVysledek);
 }
}

class App
{
 static void VolejVydel()
 {
  //pripadna vyjimka neni zachytavana
  //zadnym handlerem
  DeleniNulou.MetodaVolajiciVydel();
 }
  
 static void Main(string[] args)
 {
  try
  {
   VolejVydel();
  }
  //zde dojde ke zpracovani pripadne vyjimky
  //vyvolane metodou MetodaVolajiciVydel
  catch (DivideByZeroException)
  {
   Console.WriteLine("V metode VolejVydel nastala chyba, deleni nulou");
  }
   Console.ReadLine();
 }
}

Jak je vidět ve třídě DeleniNulou, případná výjimka vyvolaná metodou Vydel není zachytávána ihned v metodě MetodaVolajiciVydel. Metodu MetodaVolajiciVydel volá aplikační třída App ve své metodě VolejVydel, kde také k zachycení nedojde, jelikož není přítomný žádný handler. Případně vyvolaná výjimka je zachycena až v metodě Main aplikační třídy App, která volá metodu VolejVydel, kde se nalézá handler přímo pro konkrétní typ výjimky DivideByZeroException. Z toho je zřejmé jak je vyvolaná výjimka předávána volajícím metodám, kde může být zpracována.

Vlastnost Message třídy System.Exception

Jak již víme s předchozího dílu, výjimka je objekt nesoucí informace o vzniklém výjimečném stavu. Informace o nastalém stavu je možné z objektu výjimky získat přečtením jeho vlastností. Často používanou vlastností je vlastnost Message, jejímž přečtením můžeme získat řetězec znaků představující vysvětlení důvodu nastalého stavu. Vlastnosti Message můžeme využít při vyhazování nové výjimky a to použitím přetížené verze konstruktoru třídy System.Exception, do kterého jako parametr zadáme řetězec představující tuto vlastnost. Po rozšíření našich vědomostí o tuto skutečnost napíšeme příklad s výjimkou představující dělení nulou třeba takto:

public class DeleniNulou
{
 public static float Vydel(int a,int b)
 {
  if (b == 0)
   //vyhozeni vyjimky pouzitim pretizene
   //verze konstruktoru pro zadani
   //vlastnosti Message
   throw new DivideByZeroException("Delitel je roven nule!");
  return a / b;
 }

class App
{

 static void Main(string[] args)
 {
  try
  {
   DeleniNulou.Vydel(5,0);
  }
  catch (DivideByZeroException ex)
  {
   //vypsani vlastnosti Message nastale vyjimky
   Console.WriteLine(ex.Message);
  }
  Console.ReadLine();
 }
}

Vlastnost StackTrace

Přečtením této vlastnosti objektu výjimky získáme trasování zásobníku, což je hierarchický výpis volaných metod, který začíná u původce výjimky. Na základě této informace jsme schopni lépe odhalit vzniklý problém, protože vidíme ve které metodě byla výjimka vyhozena a jak byla předávána až k jejímu zachycení. Takže pokud bychom v předchozím příkladu použili místo výpisu vlastnosti Message vlastnost StackTrace vidělo bychom toto:

   at PrikladyZive14.DeleniNulou.Vydel(Int32 a, Int32 b) in c:\documents and settings\petr puš\dokumenty\visual studio projects\prikladyzive\prikladyzive14\deleninulou.cs:line 13
   at Zive14TestApp.App.Main(String[] args) in c:\documents and settings\petr puš\dokumenty\visual studio projects\prikladyzive\zive14testapp\app.cs:line 19

Vytváření vlastních výjimek

Postupem času, se při programování s používáním výjimek s velkou pravděpodobností dostanete do situace, kdy vám vestavěné typy výjimek .NET frameworku přestanou stačit. Zajisté budete chtít vytvořit vlastní typ výjimky, který se pro danou výjimečnou událost hodí více než jakákoli z vestavěných, nebo se mezi nimi dokonce žádná, ani vzdáleně podobná, nevyskytuje. Toho lze později využít při vytváření handlerů pro více typů výjimek, protože na naši vlastní výjimku můžeme vytvořit speciální handler.

Vlastní výjimku v .NET frameworku vytvoříme odvozením od nějaké existující třídy reprezentující výjimku. Ve velkém počtu případů nám vhodně jako bázová třída poslouží společný předek všech výjimek, tedy třída System.Exception. Pokud je to však možné, tak použijte existujícího typu výjimky, který je významově blízký nově vytvářené výjimce. Jelikož hlavní důvod pro vytvoření vlastní výjimky je nejčastěji v získání nového typu, který bude později handlery zachytáván, stačí pouze uvést při deklaraci třídy předka a nepřekrývat žádné členy.

public class MojeVyjimka : System.Exception {}

Po takovémto vytvoření vlastní výjimky ji již můžeme v našich třídách nesměle používat jako kteroukoliv jinou, jak zobrazuje následující příklad.

class MojeVyjimkaPouziti
{
 public static void MetodaVyvolavajiciMojiVyjimku()
 {
  //nejaky kod metody
  throw new MojeVyjimka();
 }

 static void MetodaHandler()
 {
  try
  {
   MetodaVyvolavajiciMojiVyjimku();
  }
  catch(MojeVyjimka ex)
  {
   //kod pro zpracovani vyjimky typu MojeVyjimka
  }
  catch(Exception ex)
  {
   //kod pro zpracovani ostatnich vyjimek
  }
 }
}

Omezení při definici více handlerů

V .NET frameworku není povoleno při vytváření více handlerů, definovat handler pro obecnější typy výjimek nad handlery pro konkrétnější typy výjimek. Je to logické zabránění chybnému zachytávání výjimek, kde by handler pro obecnější typ výjimky zpracoval i výjimky, které by měly být správně zpracovány handlerem pro konkrétnější typ. Pokud bychom předcházející příklad změnili do následující podoby, program by nešel zkompilovat.

static void MetodaHandler()
{
 try
 {
  MetodaVyvolavajiciMojiVyjimku();
 }
 //tento handler by zabranil provedeni
 //konkretnejsiho handleru
 catch(Exception ex)
 {
  //kod pro zpracovani ostatnich vyjimek
 }
 catch(MojeVyjimka ex)
 {
  //kod pro zpracovani vyjimky typu MojeVyjimka
 }
 
}

Opakované vyhození výjimky

Občas můžeme potřebovat při zachycení výjimky provést pouze určitou část akcí a zbylou část operací ponechat na volajících metodách. Toho lze docílit pomocí takzvaného opakovaného vyhození výjimky, kdy použijeme slovíčko throw na již zachycenou instanci výjimky. Tím dosáhneme požadovaného výsledku.

public class Rethrow
{
 public static void MetodaVolajiciVyjimku()
 {
  //nejaky kod metody
  throw new MojeVyjimka();
 }

 public static void MetodaHandler()
 {
  try
  {
   MetodaVolajiciVyjimku();
  }
  catch(MojeVyjimka ex)
  {
   //provedeni urcite casti akci
   //opakovane vyhozeni
   throw ex;
  }
 }
}

Zabalení výjimky

Kromě opakovaného vyhození výjimky je také možné vzniklý objekt výjimky zabalit do jiného objektu výjimky a ten následně vyhodit. To je vhodné v případě, když chceme k výjimce přidat nějaké dodatečné informace a vyhodit nový objekt výjimky, který může být i třeba jiného typu. K zabalení výjimky použijeme jednu z přetížených verzí konstruktoru, který je definován na třídě System.Exception. Tento konstruktor od nás očekává řetězec představující vlastnost Message a zabalovanou(vnitřní) výjimku.

public class ExceptionBoxing
{
 public static void MetodaVolajiciVyjimku()
 {
  try
  {
   DeleniNulou.Vydel(5,0);
  }
  catch(DivideByZeroException ex)
  {
   //zabaleni vyjimky
   throw new Exception("Delitel je roven nule!", ex);
  }
 }
}

class App

 static void Main(string[] args)
 {
  try
  {
   ExceptionBoxing.MetodaVolajiciVyjimku();
  }
  catch (Exception ex)
  {
   //zobrazeni vyjimky pomoci metody ToString
   Console.WriteLine(ex.ToString());
  }
  Console.ReadLine();
 }
}

Pro výpis výjimky jsem záměrně použil metodu ToString, která je překryta takovým způsobem, že nám v tomto případě zobrazí informace o přítomné vnitřní výjimce. Uvedený příklad tedy vygeneruje následující výstup:

System.Exception: Delitel je roven nule! ---> System.DivideByZeroException: Delitel je roven nule!
at PrikladyZive14.DeleniNulou.Vydel(Int32 a, Int32 b) in c:\documents and settings\petr puš\dokumenty\visual studio projects\prikladyzive\prikladyzive14\deleninulou.cs:line 13
at PrikladyZive14.ExceptionBoxing.MetodaVolajiciVyjimku() in c:\documents and settings\petr puš\dokumenty\visual studio projects\prikladyzive\prikladyzive14\exceptionboxing.cs:line 11
--- End of inner exception stack trace ---
at PrikladyZive14.ExceptionBoxing.MetodaVolajiciVyjimku() in c:\documents and settings\petr puš\dokumenty\visual studio projects\prikladyzive\prikladyzive14\exceptionboxing.cs:line 16
at Zive14TestApp.App.Main(String[] args) in c:\documents and settings\petr puš\dokumenty\visual studio projects\prikladyzive\zive14testapp\app.cs:line 19

Pokud bychom z nějakého důvodu potřebovali získat objekt vnitřní výjimky použijeme vlastnost InnerException na zachyceném objektu výjimky.

class App

 static void Main(string[] args)
 {
  try
  {
   ExceptionBoxing.MetodaVolajiciVyjimku();
  }
  catch (Exception ex)
  {
   Exception lInnerEx = ex.InnerException;
   Console.WriteLine(lInnerEx.ToString());
  }
  Console.ReadLine();
 }
}

Zdrojové kódy příkladů je možné nalézt zde.

Příště se seznámíme s velmi zajímavou vlastností jazyku C#, kterou jsou delegáti.

Diskuze (5) Další článek: Jihlavská ZOO vítá první návštěvníky z internetu

Témata článku: Software, Microsoft, Programování, Message, Společný předek, Public, Petr, Catch, Díl, Kody, Strong, Druh, Výjimečná vlastnost


Určitě si přečtěte

Vybrali jsme 21 programovatelných hraček a stavebnic pro děti i jejich rodiče

Vybrali jsme 21 programovatelných hraček a stavebnic pro děti i jejich rodiče

** Získejte děti pro matematiku a základy techniky ** Kupte jim hračku nebo stavebnici, které vdechnou vlastní život ** Vybrali jsme 21 stavebnic pro malé caparty i budoucí experty na A.I.

Jakub Čížek | 10

Co je TikTok: Svérázná sociální síť chytla mladé uživatele, už jich má už 1,5 miliardy

Co je TikTok: Svérázná sociální síť chytla mladé uživatele, už jich má už 1,5 miliardy

** Sociální síť TikTok získala stamiliony uživatelů a stále roste ** Jaký obsah na ní najdete a co můžete v jejím rámci čekat? ** Je to zábava pro mladé, nebo platforma pro úchyláky?

Karel Kilián | 34

10 mýtů a polopravd o bateriích, kterým možná ještě věříte

10 mýtů a polopravd o bateriích, kterým možná ještě věříte

** Kolem baterií a akumulátorů koluje řada mýtů, nepravd a polopravd ** Dnes vám devět z nich zkusíme vyvrátit na základě faktů ** Většina z nich totiž neplatí pro moderní lithiové baterie

Karel Kilián, David Polesný | 99

Antivir zdarma: 8 bezplatných řešení, která zatočí s havětí v počítači

Antivir zdarma: 8 bezplatných řešení, která zatočí s havětí v počítači

** Součástí Windows 10 je integrovaný antivirový program. Stačí to? ** Představíme vám sedm aplikací na boj proti virům a malwaru ** Všechny jsou k dispozici zdarma a některé ani nemusíte instalovat

Karel Kilián | 31

Pojďme programovat elektroniku: Rádiový čip, který má skoro každá bezdrátová myš

Pojďme programovat elektroniku: Rádiový čip, který má skoro každá bezdrátová myš

** Bezdrátové myši řídí čip od Nordic Semiconductors ** Jeho rádiové vysílače si před lety oblíbila i komunita kutilů ** Dnes si je vyzkoušíme v praxi

Jakub Čížek | 9

Nejlepší notebooky do 10 000 korun: Co koupit a čemu se raději vyhnout

Nejlepší notebooky do 10 000 korun: Co koupit a čemu se raději vyhnout

** Do deseti tisíc korun lze dnes koupit slušné notebooky ** V nabídce ale i tak převládají zastaralé a pomalé modely ** Poradíme, jak dobře vybrat i s omezeným rozpočtem

David Polesný | 102


Aktuální číslo časopisu Computer

Megatest: 20 powerbank s USB-C

Test: mobily do 3 500 Kč

Radíme s výběrem routeru

Tipy na nejlepší vánoční dárky