Použití výjimek
V jazyce C# se chyby v programu za běhu šíří prostřednictvím programu pomocí mechanismu označovaného jako výjimky. Výjimky jsou vyvolány kódem, který narazí na chybu a zachytil kód, který může chybu opravit. Výjimky můžou vyvolat modul runtime .NET nebo kód v programu. Jakmile dojde k vyvolání výjimky, rozšíří se zásobník volání, dokud catch
se nenajde příkaz pro výjimku. Nezachycené výjimky zpracovává obecná obslužná rutina výjimky poskytovaná systémem, který zobrazuje dialogové okno.
Výjimky jsou reprezentovány třídami odvozenými z Exception. Tato třída identifikuje typ výjimky a obsahuje vlastnosti s podrobnostmi o výjimce. Vyvolání výjimky zahrnuje vytvoření instance odvozené třídy výjimky, volitelně konfigurace vlastností výjimky a následné vyvolání objektu pomocí klíčového throw
slova. Příklad:
class CustomException : Exception
{
public CustomException(string message)
{
}
}
private static void TestThrow()
{
throw new CustomException("Custom exception in TestThrow()");
}
Po vyvolání výjimky modul runtime zkontroluje aktuální příkaz a zjistí, jestli je v try
bloku. Pokud ano, zkontrolují se všechny catch
bloky přidružené k try
bloku a zkontrolují, jestli můžou výjimku zachytit. Catch
bloky obvykle určují typy výjimek; pokud je typ catch
bloku stejný typ jako výjimka nebo základní třída výjimky, catch
může blok zpracovat metodu. Příklad:
try
{
TestThrow();
}
catch (CustomException ex)
{
System.Console.WriteLine(ex.ToString());
}
Pokud příkaz, který vyvolá výjimku, není v try
bloku nebo pokud try
blok, který ho uzavře, nemá žádný odpovídající catch
blok, modul runtime zkontroluje volající metodu try
pro příkaz a catch
bloky. Modul runtime pokračuje v zásobníku volání a hledá kompatibilní catch
blok. catch
Po nalezení a spuštění bloku se ovládací prvek předá dalšímu příkazu za tímto catch
blokem.
Příkaz try
může obsahovat více než jeden catch
blok. První catch
příkaz, který dokáže zpracovat výjimku, se spustí. Všechny následující catch
příkazy, i když jsou kompatibilní, se ignorují. Zachytávání bloků od nejvýraznějších (nebo nejvíce odvozených) po nejméně specifické Příklad:
using System;
using System.IO;
namespace Exceptions
{
public class CatchOrder
{
public static void Main()
{
try
{
using (var sw = new StreamWriter("./test.txt"))
{
sw.WriteLine("Hello");
}
}
// Put the more specific exceptions first.
catch (DirectoryNotFoundException ex)
{
Console.WriteLine(ex);
}
catch (FileNotFoundException ex)
{
Console.WriteLine(ex);
}
// Put the least specific exception last.
catch (IOException ex)
{
Console.WriteLine(ex);
}
Console.WriteLine("Done");
}
}
}
Před spuštěním catch
bloku modul runtime kontroluje finally
bloky. Finally
bloky umožňují programátoru vyčistit jakýkoli nejednoznačný stav, který by mohl být ponechán z přerušeného try
bloku, nebo uvolnit jakékoli externí prostředky (například grafické popisovače, připojení k databázi nebo streamy souborů) bez čekání na uvolňování paměti v modulu runtime k dokončení objektů. Příklad:
static void TestFinally()
{
FileStream? file = null;
//Change the path to something that works on your machine.
FileInfo fileInfo = new System.IO.FileInfo("./file.txt");
try
{
file = fileInfo.OpenWrite();
file.WriteByte(0xF);
}
finally
{
// Closing the file allows you to reopen it immediately - otherwise IOException is thrown.
file?.Close();
}
try
{
file = fileInfo.OpenWrite();
Console.WriteLine("OpenWrite() succeeded");
}
catch (IOException)
{
Console.WriteLine("OpenWrite() failed");
}
}
Pokud WriteByte()
vyvoláte výjimku, kód ve druhém try
bloku, který se pokusí znovu otevřít soubor, selže, pokud file.Close()
není volána, a soubor zůstane uzamčený. Vzhledem k tomu finally
, že se bloky spouští i v případě, že je vyvolána výjimka, finally
umožňuje blok v předchozím příkladu správně zavřít soubor a pomáhá vyhnout se chybě.
Pokud se v zásobníku volání po vyvolání výjimky nenajde žádný kompatibilní catch
blok, dojde k jedné ze tří věcí:
- Pokud je výjimka v finalizátoru, finalizátor je přerušen a je volána základní finalizátor, pokud existuje.
- Pokud zásobník volání obsahuje statický konstruktor nebo inicializátor statického pole, TypeInitializationException vyvolá se vyvolá původní výjimka přiřazená vlastnosti InnerException nové výjimky.
- Pokud je dosaženo spuštění vlákna, vlákno se ukončí.