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#.

Viz také