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čí.