Zpracování výjimek (Průvodce programováním v C#)
Programátoři jazyka C# používají blok try k dělení kódu, který může být ovlivněn výjimkou. Přidružené bloky catch se používají ke zpracování všech výsledných výjimek. Blok nakonec obsahuje kód, který se spustí bez ohledu na to, jestli je v try
bloku vyvolán výjimka, například uvolnění prostředků přidělených v try
bloku. Blok try
vyžaduje jeden nebo více přidružených catch
bloků, finally
blok nebo obojí.
Následující příklady ukazují try-catch
příkaz, try-finally
příkaz a try-catch-finally
příkaz.
try
{
// Code to try goes here.
}
catch (SomeSpecificException ex)
{
// Code to handle the exception goes here.
// Only catch exceptions that you know how to handle.
// Never catch base class System.Exception without
// rethrowing it at the end of the catch block.
}
try
{
// Code to try goes here.
}
finally
{
// Code to execute after the try block goes here.
}
try
{
// Code to try goes here.
}
catch (SomeSpecificException ex)
{
// Code to handle the exception goes here.
}
finally
{
// Code to execute after the try (and possibly catch) blocks
// goes here.
}
Blok try
bez catch
bloku způsobí finally
chybu kompilátoru.
Zachytávání bloků
catch
Blok může určit typ výjimky, která se má zachytit. Specifikace typu se nazývá filtr výjimek. Typ výjimky by měl být odvozen z Exception. Obecně platí, že jako filtr výjimek nezadávejte Exception , pokud nevíte, jak zpracovat všechny výjimky, které by mohly být vyvolány v try
bloku, nebo jste zahrnuli throw
příkaz na konec catch
bloku.
Více catch
bloků s různými třídami výjimek lze zřetězit dohromady. Bloky catch
se v kódu vyhodnocují shora dolů, ale pro každou výjimku, která je vyvoláná, se provede pouze jeden catch
blok. Spustí se první catch
blok, který určuje přesný typ nebo základní třídu vyvolané výjimky. Pokud žádný catch
blok neurčí odpovídající třídu výjimky, catch
je vybrán blok, který nemá žádný typ, pokud je v příkazu. Nejprve je důležité umístit catch
bloky s nejvýraznějšími třídami výjimek (tj. nejrozpočítovanějšími).
Zachyťte výjimky, pokud jsou splněny následující podmínky:
- Máte dobrý přehled o tom, proč může být vyvolán výjimka, a můžete implementovat konkrétní obnovení, například vyzvat uživatele k zadání nového názvu souboru při zachycení objektu FileNotFoundException .
- Můžete vytvořit a vyvolat novou, konkrétnější výjimku.
int GetInt(int[] array, int index) { try { return array[index]; } catch (IndexOutOfRangeException e) { throw new ArgumentOutOfRangeException( "Parameter index is out of range.", e); } }
- Chcete částečně zpracovat výjimku, než ji předáte pro další zpracování. V následujícím příkladu
catch
se blok používá k přidání položky do protokolu chyb před opětovným zvětšováním výjimky.try { // Try to access a resource. } catch (UnauthorizedAccessException e) { // Call a custom error logging procedure. LogError(e); // Re-throw the error. throw; }
Můžete také zadat filtry výjimek pro přidání logického výrazu do klauzule catch. Filtry výjimek označují, že konkrétní klauzule catch odpovídá pouze tehdy, když je tato podmínka pravdivá. V následujícím příkladu obě klauzule catch používají stejnou třídu výjimek, ale je zaškrtnutá další podmínka pro vytvoření jiné chybové zprávy:
int GetInt(int[] array, int index)
{
try
{
return array[index];
}
catch (IndexOutOfRangeException e) when (index < 0)
{
throw new ArgumentOutOfRangeException(
"Parameter index cannot be negative.", e);
}
catch (IndexOutOfRangeException e)
{
throw new ArgumentOutOfRangeException(
"Parameter index cannot be greater than the array size.", e);
}
}
Filtr výjimek, který vždy vrací false
, lze použít k prozkoumání všech výjimek, ale ne ke zpracování. Typickým použitím je protokolování výjimek:
public class ExceptionFilter
{
public static void Main()
{
try
{
string? s = null;
Console.WriteLine(s.Length);
}
catch (Exception e) when (LogException(e))
{
}
Console.WriteLine("Exception must have been handled");
}
private static bool LogException(Exception e)
{
Console.WriteLine($"\tIn the log routine. Caught {e.GetType()}");
Console.WriteLine($"\tMessage: {e.Message}");
return false;
}
}
Metoda LogException
vždy vrátí false
, žádná catch
klauzule používající tento filtr výjimky odpovídá. Klauzule catch může být obecná, using System.Exceptiona novější klauzule mohou zpracovávat konkrétnější třídy výjimek.
Konečné bloky
Blok finally
umožňuje vyčistit akce prováděné v try
bloku. Pokud je blok k dispozici, try
spustí se finally
za blokem a za všemi odpovídajícími catch
bloky. finally
Blok se vždy spustí, ať už je vyvolán výjimka, nebo catch
blok odpovídající typu výjimky.
Blok finally
lze použít k uvolnění prostředků, jako jsou streamy souborů, připojení k databázi a grafické popisovače, aniž byste čekali na uvolnění paměti v modulu runtime k dokončení objektů.
V následujícím příkladu finally
se blok používá k zavření souboru, který je otevřen v try
bloku. Všimněte si, že stav popisovače souboru je zaškrtnutý před zavřením souboru. try
Pokud blok nemůže soubor otevřít, má popisovač souboru stále hodnotu null
a finally
blok se ho nepokouší zavřít. Místo toho, pokud je soubor úspěšně otevřen v try
bloku, finally
blok zavře otevřený soubor.
FileStream? file = null;
FileInfo fileinfo = new System.IO.FileInfo("./file.txt");
try
{
file = fileinfo.OpenWrite();
file.WriteByte(0xF);
}
finally
{
// Check for null because OpenWrite might have failed.
file?.Close();
}
Specifikace jazyka C#
Další informace naleznete v tématu Výjimky a příkaz try ve specifikaci jazyka C#. Specifikace jazyka je úplným a rozhodujícím zdrojem pro syntaxi a použití jazyka C#.