Příkazy zpracování výjimek - throw
, try-catch
try-finally
, atry-catch-finally
Příkazy a try
příkazy slouží throw
k práci s výjimkami. Pomocí příkazu throw
vyvoláte výjimku. Pomocí příkazu try
můžete zachytit a zpracovat výjimky, ke kterým může dojít během provádění bloku kódu.
Příkaz throw
Příkaz throw
vyvolá výjimku:
if (shapeAmount <= 0)
{
throw new ArgumentOutOfRangeException(nameof(shapeAmount), "Amount of shapes must be positive.");
}
throw e;
V příkazu musí být výsledek výrazu e
implicitně konvertibilní na System.Exception.
Můžete použít předdefinované třídy výjimek, například ArgumentOutOfRangeException nebo InvalidOperationException. .NET také poskytuje následující pomocné metody pro vyvolání výjimek za určitých podmínek: ArgumentNullException.ThrowIfNull a ArgumentException.ThrowIfNullOrEmpty. Můžete také definovat vlastní třídy výjimek, které jsou odvozeny z System.Exception. Další informace naleznete v tématu Vytváření a vyvolávání výjimek.
catch
Uvnitř bloku můžete použít throw;
příkaz k opětovnému vyvolání výjimky, která je zpracována blokemcatch
:
try
{
ProcessShapes(shapeAmount);
}
catch (Exception e)
{
LogError(e, "Shape processing failed.");
throw;
}
Poznámka:
throw;
zachová původní trasování zásobníku výjimky, která je uložena Exception.StackTrace ve vlastnosti. Naopak, throw e;
aktualizuje StackTrace vlastnost e
.
Při vyvolání výjimky modul CLR (Common Language Runtime) vyhledá catch
blok , který může tuto výjimku zpracovat. Pokud aktuálně spuštěná metoda neobsahuje takový catch
blok, CLR se podívá na metodu, která volala aktuální metodu atd. Pokud se nenajde žádný catch
blok, CLR ukončí spuštěné vlákno. Další informace najdete v části Jak se zpracovávají výjimky specifikace jazyka C#.
Výraz throw
Můžete také použít throw
jako výraz. To může být praktické v řadě případů, mezi které patří:
podmíněný operátor. Následující příklad používá
throw
výraz k vyvolání ArgumentException , když je předané poleargs
prázdné:string first = args.Length >= 1 ? args[0] : throw new ArgumentException("Please supply at least one argument.");
operátor null-coalescing. Následující příklad používá
throw
výraz k vyvolání ArgumentNullException , když řetězec přiřadit k vlastnosti jenull
:public string Name { get => name; set => name = value ?? throw new ArgumentNullException(paramName: nameof(value), message: "Name cannot be null"); }
výraz-bodied lambda nebo metoda. Následující příklad používá
throw
výraz k vyvolání InvalidCastException označující, že převod na DateTime hodnotu není podporován:DateTime ToDateTime(IFormatProvider provider) => throw new InvalidCastException("Conversion to a DateTime is not supported.");
Příkaz try
Příkaz můžete použít try
v některém z následujících formulářů: try-catch
– ke zpracování výjimek, ke kterým může dojít při provádění kódu uvnitř try
bloku, – k určení kódu, try-finally
který se spustí při opuštění try
bloku, a try-catch-finally
- jako kombinaci předchozích dvou formulářů.
Příkaz try-catch
try-catch
Příkaz použijte ke zpracování výjimek, ke kterým může dojít během provádění bloku kódu. Umístěte kód tam, kde může do bloku dojít k výjimce try
. Pomocí klauzule catch zadejte základní typ výjimek, které chcete zpracovat v odpovídajícím catch
bloku:
try
{
var result = Process(-3, 4);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (ArgumentException e)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
Můžete zadat několik klauzulí catch:
try
{
var result = await ProcessAsync(-3, 4, cancellationToken);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (ArgumentException e)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
catch (OperationCanceledException)
{
Console.WriteLine("Processing is cancelled.");
}
Pokud dojde k výjimce, jsou klauzule catch zkoumány v zadaném pořadí shora dolů. Při každé vyvolání výjimky se spustí maximálně jeden catch
blok. Jak ukazuje předchozí příklad, můžete vynechat deklaraci proměnné výjimky a zadat pouze typ výjimky v klauzuli catch. Klauzule catch bez jakéhokoli zadaného typu výjimky odpovídá jakékoli výjimce a pokud existuje, musí být poslední klauzulí catch.
Pokud chcete znovu vyvolat zachycenou výjimku, použijte příkazthrow
, jak ukazuje následující příklad:
try
{
var result = Process(-3, 4);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (Exception e)
{
LogError(e, "Processing failed.");
throw;
}
Poznámka:
throw;
zachová původní trasování zásobníku výjimky, která je uložena Exception.StackTrace ve vlastnosti. Naopak, throw e;
aktualizuje StackTrace vlastnost e
.
when
Filtr výjimek
Spolu s typem výjimky můžete také zadat filtr výjimky, který dále prozkoumá výjimku a rozhodne, jestli odpovídající catch
blok zpracovává tuto výjimku. Filtr výjimek je logický výraz, který následuje za when
klíčovým slovem, jak ukazuje následující příklad:
try
{
var result = Process(-3, 4);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (Exception e) when (e is ArgumentException || e is DivideByZeroException)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
Předchozí příklad používá filtr výjimek k poskytnutí jednoho catch
bloku pro zpracování výjimek dvou zadaných typů.
Pokud se rozlišují filtry výjimek, můžete zadat několik catch
klauzulí pro stejný typ výjimky. Jedna z těchto klauzulí nemusí mít žádný filtr výjimek. Pokud taková klauzule existuje, musí to být poslední z klauzulí, které určují tento typ výjimky.
catch
Pokud má klauzule filtr výjimek, může určit typ výjimky, který je stejný jako nebo menší odvozený než typ catch
výjimky klauzule, která se zobrazí za ní. Pokud je například k dispozici filtr výjimek, catch (Exception e)
klauzule nemusí být poslední klauzulí.
Výjimky v asynchronních metodách a metodách iterátoru
Pokud v asynchronní funkci dojde k výjimce, rozšíří se do volajícího funkce, když očekáváte výsledek funkce, jak ukazuje následující příklad:
public static async Task Run()
{
try
{
Task<int> processing = ProcessAsync(-1);
Console.WriteLine("Launched processing.");
int result = await processing;
Console.WriteLine($"Result: {result}.");
}
catch (ArgumentException e)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
// Output:
// Launched processing.
// Processing failed: Input must be non-negative. (Parameter 'input')
}
private static async Task<int> ProcessAsync(int input)
{
if (input < 0)
{
throw new ArgumentOutOfRangeException(nameof(input), "Input must be non-negative.");
}
await Task.Delay(500);
return input;
}
Pokud v metodě iterátoru dojde k výjimce, rozšíří se do volajícího pouze v případě, že iterátor přejde na další prvek.
Příkaz try-finally
try-finally
V příkazu finally
se blok spustí, když ovládací prvek opustí try
blok. Ovládací prvek může blok opustit try
v důsledku
- normální provádění,
- provedení příkazu skoku (to znamená ,
return
,break
,continue
nebo ) nebogoto
- šíření výjimky z
try
bloku.
Následující příklad používá finally
blok k resetování stavu objektu před tím, než ovládací prvek opustí metodu:
public async Task HandleRequest(int itemId, CancellationToken ct)
{
Busy = true;
try
{
await ProcessAsync(itemId, ct);
}
finally
{
Busy = false;
}
}
Blok můžete také použít finally
k vyčištění přidělených prostředků použitých v try
bloku.
Poznámka:
Pokud typ prostředku implementuje IDisposable nebo IAsyncDisposable rozhraní, zvažte using
příkaz. Příkaz using
zajistí, že získané prostředky budou uvolněny, když ovládací prvek opustí using
příkaz. Kompilátor transformuje using
příkaz na try-finally
příkaz.
finally
Spuštění bloku závisí na tom, jestli se operační systém rozhodne aktivovat operaci uvolnění výjimky. Jediné případy, kdy finally
se bloky nespustí, zahrnují okamžité ukončení programu. K takovému ukončení může dojít například kvůli Environment.FailFast volání nebo výjimce OverflowException InvalidProgramException . Většina operačních systémů provádí rozumné vyčištění prostředků v rámci zastavení a uvolnění procesu.
Příkaz try-catch-finally
K zpracování výjimek, ke kterým může dojít během provádění try
bloku, použijete try-catch-finally
příkaz oba a zadáte kód, který se musí spustit, když ovládací prvek opustí try
příkaz:
public async Task ProcessRequest(int itemId, CancellationToken ct)
{
Busy = true;
try
{
await ProcessAsync(itemId, ct);
}
catch (Exception e) when (e is not OperationCanceledException)
{
LogError(e, $"Failed to process request for item ID {itemId}.");
throw;
}
finally
{
Busy = false;
}
}
Při zpracování výjimky blokem catch
finally
se blok spustí po spuštění catch
tohoto bloku (i když během provádění catch
bloku dojde k jiné výjimce). Informace o catch
příkazech a finally
blocích naleznete v části Příkaz try-catch
a Příkaztry-finally
.
specifikace jazyka C#
Další informace najdete v následujících částech specifikace jazyka C#: