Vytvoření a vyvolání výjimek

Výjimky se používají k označení, že při spuštění programu došlo k chybě. Objekty výjimky, které popisují chybu, jsou vytvořeny a následně vyvolány příkazem nebo výrazemthrow. Modul runtime pak vyhledá nejkomppatibilnější obslužnou rutinu výjimek.

Programátoři by měli vyvolat výjimky, pokud jsou splněny některé z následujících podmínek:

  • Metoda nemůže dokončit definované funkce. Pokud má například parametr metody neplatnou hodnotu:

    static void CopyObject(SampleClass original)
    {
        _ = original ?? throw new ArgumentException("Parameter cannot be null", nameof(original));
    }
    
  • Na základě stavu objektu se vytvoří nevhodné volání objektu. Jedním z příkladů může být pokus o zápis do souboru jen pro čtení. V případech, kdy stav objektu neumožňuje operaci, vyvolá instanci InvalidOperationException nebo objekt na základě odvození této třídy. Následující kód je příkladem metody, která vyvolá InvalidOperationException objekt:

    public class ProgramLog
    {
        FileStream logFile = null!;
        public void OpenLog(FileInfo fileName, FileMode mode) { }
    
        public void WriteLog()
        {
            if (!logFile.CanWrite)
            {
                throw new InvalidOperationException("Logfile cannot be read-only");
            }
            // Else write data to the log and return.
        }
    }
    
  • Když argument metody způsobí výjimku. V tomto případě by se měla zachytit původní výjimka a ArgumentException měla by se vytvořit instance. Původní výjimka by měla být předána konstruktoru ArgumentExceptionInnerException jako parametr:

    static int GetValueFromArray(int[] array, int index)
    {
        try
        {
            return array[index];
        }
        catch (IndexOutOfRangeException e)
        {
            throw new ArgumentOutOfRangeException(
                "Parameter index is out of range.", e);
        }
    }
    

    Poznámka:

    Předchozí příklad ukazuje, jak použít InnerException vlastnost. Je záměrně zjednodušená. V praxi byste měli před použitím zkontrolovat, jestli je index v rozsahu. Tuto techniku zabalení výjimky můžete použít, když člen parametru vyvolá výjimku, kterou jste nemohli před voláním člena předvídat.

Výjimky obsahují vlastnost s názvem StackTrace. Tento řetězec obsahuje název metod v aktuálním zásobníku volání společně s názvem souboru a číslem řádku, kde byla pro každou metodu vyvolán výjimka. Objekt StackTrace se vytvoří automaticky modulem CLR (Common Language Runtime) z bodu throw příkazu, takže výjimky musí být vyvolány z bodu, kde by mělo začínat trasování zásobníku.

Všechny výjimky obsahují vlastnost s názvem Message. Tento řetězec by měl být nastavený tak, aby vysvětlil důvod výjimky. Informace citlivé na zabezpečení by neměly být vloženy do textu zprávy. Kromě Message, ArgumentException obsahuje vlastnost pojmenovaná ParamName , která by měla být nastavena na název argumentu, který způsobil výjimku vyvolání. V setter ParamName vlastnosti by měla být nastavena na value.

Veřejné a chráněné metody můžou vyvolat výjimky vždy, když nemůžou dokončit zamýšlené funkce. Vyvolaná třída výjimky je nejvýraznější dostupná výjimka, která odpovídá chybám. Tyto výjimky by měly být zdokumentované jako součást funkcí třídy a odvozené třídy nebo aktualizace původní třídy by měly zachovat stejné chování pro zpětnou kompatibilitu.

Co je potřeba se vyhnout při vyvolání výjimek

Následující seznam uvádí postupy, které se mají vyhnout při vyvolání výjimek:

  • Nepoužívejte výjimky ke změně toku programu jako součást běžného provádění. Pomocí výjimek můžete hlásit a zpracovat chybové stavy.
  • Výjimky by se neměly vracet jako návratová hodnota nebo parametr místo vyvolání.
  • Nevyhazujte System.Exception, , System.SystemExceptionSystem.NullReferenceExceptionani System.IndexOutOfRangeException záměrně z vlastního zdrojového kódu.
  • Nevytvávejte výjimky, které se dají vyvolat v režimu ladění, ale ne v režimu vydání. Pokud chcete identifikovat chyby za běhu během vývojové fáze, použijte místo toho příkaz Debug Assert.

Výjimky v metodách vracejících úkoly

Metody deklarované s modifikátorem async mají některé zvláštní aspekty, pokud jde o výjimky. Výjimky vyvolané v async metodě jsou uloženy ve vrácené úloze a neobjevují se, dokud například úkol nebude očekáván. Další informace o uložených výjimkách naleznete v tématu Asynchronní výjimky.

Před zadáním asynchronních částí vašich metod doporučujeme ověřit argumenty a vyvolat odpovídající výjimky, například ArgumentException a ArgumentNullException. To znamená, že tyto výjimky ověřování by se měly objevit synchronně před zahájením práce. Následující fragment kódu ukazuje příklad, kdy pokud dojde k vyvolání výjimek, ArgumentException výjimky se objeví synchronně, zatímco by InvalidOperationException se uložily do vrácené úlohy.

// Non-async, task-returning method.
// Within this method (but outside of the local function),
// any thrown exceptions emerge synchronously.
public static Task<Toast> ToastBreadAsync(int slices, int toastTime)
{
    if (slices is < 1 or > 4)
    {
        throw new ArgumentException(
            "You must specify between 1 and 4 slices of bread.",
            nameof(slices));
    }

    if (toastTime < 1)
    {
        throw new ArgumentException(
            "Toast time is too short.", nameof(toastTime));
    }

    return ToastBreadAsyncCore(slices, toastTime);

    // Local async function.
    // Within this function, any thrown exceptions are stored in the task.
    static async Task<Toast> ToastBreadAsyncCore(int slices, int time)
    {
        for (int slice = 0; slice < slices; slice++)
        {
            Console.WriteLine("Putting a slice of bread in the toaster");
        }
        // Start toasting.
        await Task.Delay(time);

        if (time > 2_000)
        {
            throw new InvalidOperationException("The toaster is on fire!");
        }

        Console.WriteLine("Toast is ready!");

        return new Toast();
    }
}

Definování tříd výjimek

Programy mohou vyvolat předdefinovanou třídu výjimky v System oboru názvů (s výjimkou případů, kdy dříve uvedeno) nebo vytvořit vlastní třídy výjimek odvozením z Exception. Odvozené třídy by měly definovat alespoň tři konstruktory: jeden konstruktor bez parametrů, jeden, který nastaví vlastnost zprávy a jednu, která nastavuje jak vlastnosti MessageInnerException , tak vlastnosti. Příklad:

[Serializable]
public class InvalidDepartmentException : Exception
{
    public InvalidDepartmentException() : base() { }
    public InvalidDepartmentException(string message) : base(message) { }
    public InvalidDepartmentException(string message, Exception inner) : base(message, inner) { }
}

Přidejte do třídy výjimky nové vlastnosti, pokud jsou data, která poskytují, užitečná k vyřešení výjimky. Pokud jsou do odvozené třídy výjimky přidány nové vlastnosti, ToString() měly by být přepsány, aby se vrátily přidané informace.

specifikace jazyka C#

Další informace naleznete v tématu Výjimky a příkaz throw ve specifikaci jazyka C#. Specifikace jazyka je úplným a rozhodujícím zdrojem pro syntaxi a použití jazyka C#.

Viz také