This article has been localized into Czech by the community.
Zpracování výjimek
Ve všech programech se občas něco pokazí. S C# máme to štěstí, že máme dobrý kompilátor, který nám pomůže předejít některým z nejčastějších chyb. Samozřejmě nemůže vidět každou chybu, která by se mohla stát, a v těchto případech .NET framework vyvolá výjimku, aby nám řekl, že se něco pokazilo. V dřívější kapitole o polích jsem popsal, jak bychom dostali výjimku, pokud bychom se pokusili do pole vložit příliš mnoho položek. Pojďme si připomenout příklad:
using System;
using System.Collections;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int[] numbers = new int[2];
numbers[0] = 23;
numbers[1] = 32;
numbers[2] = 42;
foreach(int i in numbers)
Console.WriteLine(i);
Console.ReadLine();
}
}
}
Dobře, zkuste tento příklad spustit a uvidíte, o čem mluvím. Vidíte, co děláme špatně? Definovali jsme pole celých čísel s místem pro 2 položky, ale pokusíme se použít 3 místa. To samozřejmě vede k chybě, kterou uvidíte, pokud tento příklad spustíte. Když spustíte program ve Visual Studio, IDE nám nabídne některé možnosti pro výjimku, ale pokud se pokusíte program spustit jednoduše dvojitým kliknutím na EXE soubor, dostanete nepříjemnou chybu. Pokud víte, že by mohla nastat chyba, měli byste ji ošetřit. Zde se používají výjimky. Zde je mírně upravená verze kódu z výše:
int[] numbers = new int[2];
try
{
numbers[0] = 23;
numbers[1] = 32;
numbers[2] = 42;
foreach(int i in numbers)
Console.WriteLine(i);
}
catch
{
Console.WriteLine("Something went wrong!");
}
Console.ReadLine();
Dovolte mi představit vám vašeho nového nejlepšího přítele, pokud jde o zpracování chyb: blok try..catch. Zkuste program teď spustit a uvidíte rozdíl - místo toho, aby nám Visual Studio/Windows řeklo, že došlo k vážnému problému, můžeme říct svůj vlastní příběh. Ale nebylo by hezké, kdybychom mohli říct, co šlo špatně? Žádný problém:
catch(Exception ex)
{
Console.WriteLine("An error occured: " + ex.Message);
}
Jak vidíte, přidali jsme něco do příkazu catch. Nyní říkáme, kterou výjimku chceme zachytit, v tomto případě základ všech výjimek, Exception. Tímto způsobem získáme nějaké informace o problému, který způsobil výjimku, a výpisem vlastnosti Message dostaneme srozumitelný popis problému.
Jak jsem řekl, Exception je nejobecnější typ výjimky. Pravidla pro zpracování výjimek nám říkají, že bychom vždy měli používat co nejméně obecný typ výjimky, a v tomto případě skutečně známe přesný typ výjimky generované naším kódem. Jak? Protože nám to Visual Studio řeklo, když jsme ji nezachytili. Pokud máte pochybnosti, dokumentace obvykle popisuje, které výjimky může metoda vyvolat. Dalším způsobem, jak to zjistit, je použití třídy Exception, která nám to řekne - změňte řádek výstupu na tento:
Console.WriteLine("An error occured: " + ex.GetType().ToString());
Výsledek je, jak bylo očekáváno, IndexOutOfRangeException (Výjimka překročení rozsahu indexu). Proto bychom tuto výjimku měli ošetřit, ale nic nám nebrání v ošetření více než jedné výjimky. V některých situacích byste mohli chtít dělat různé věci v závislosti na tom, která výjimka byla vyvolána. Jednoduše změňte náš catch blok na následující:
catch(IndexOutOfRangeException ex)
{
Console.WriteLine("An index was out of range!");
}
catch(Exception ex)
{
Console.WriteLine("Some sort of error occured: " + ex.Message);
}
Jak vidíte, nejprve hledáme IndexOutOfRangeException. Kdybychom to udělali opačně, blok catch s třídou Exception by ji zachytil, protože všechny výjimky z ní vycházejí. Jinými slovy, měli byste nejprve použít co nejspecifičtější výjimky.
Ještě jedna věc, kterou byste měli vědět ohledně výjimek, je blok finally. Blok finally může být přidán k souboru bloků catch, nebo použit výhradně, v závislosti na vašich potřebách. Kód uvnitř bloku finally je vždy spuštěn - ať už dojde k výjimce, nebo ne. Je to dobré místo, pokud potřebujete zavřít odkazy na soubory nebo uvolnit objekty, které už nebudete potřebovat. Vzhledem k tomu, že naše příklady byly dosud poměrně jednoduché, skutečně jsme nepotřebovali žádné čištění, protože o to se postará sběrač odpadků (garbage collector). Ale protože se pravděpodobně setkáte se situacemi, kdy budete potřebovat blok finally, zde je rozšířená verze našeho příkladu:
int[] numbers = new int[2];
try
{
numbers[0] = 23;
numbers[1] = 32;
numbers[2] = 42;
foreach(int i in numbers)
Console.WriteLine(i);
}
catch(IndexOutOfRangeException ex)
{
Console.WriteLine("An index was out of range!");
}
catch(Exception ex)
{
Console.WriteLine("Some sort of error occured: " + ex.Message);
}
finally
{
Console.WriteLine("It's the end of our try block. Time to clean up!");
}
Console.ReadLine();
Pokud kód spustíte, uvidíte, že se provede jak první blok výjimky, tak blok finally. Pokud odeberete řádek, který přidává číslo 42 do pole, uvidíte, že je dosaženo pouze bloku finally.
Další důležitou částí, kterou byste měli znát o výjimkách, je to, jak ovlivňují metodu, ve které k výjimkám dochází. Ne všechny nezachycené výjimky jsou pro vaši aplikaci fatální, ale když nejsou, neměli byste očekávat, že bude proveden zbývající kód metody. Na druhou stranu, pokud výjimku ošetříte, budou provedeny pouze řádky po bloku try. V našem příkladu cyklus, který vypisuje hodnoty pole, není nikdy dosažen, protože blok try přejde přímo na blok(y) catch/finally, jakmile je výjimka vyhozena. Nicméně poslední řádek, kde čteme z konzole, aby aplikace okamžitě neukončila, je dosažen. Měli byste to mít vždy na paměti, když konstruujete bloky try.