Megosztás:


Kivételek használata

A C#-ban a program futásidejű hibáit a program egy kivételeknek nevezett mechanizmussal propagálja. A kivételeket olyan kód okozza, amely hibát tapasztal, és a hibát kijavító kód észleli. A kivételeket a .NET-futtatókörnyezet vagy a program kódja is okozhatja. A kivétel eldobása után a hívásveremben terjed tovább, amíg meg nem talál catch egy, a kivételre vonatkozó utasítást. A nem tapasztalt kivételeket a párbeszédpanelt megjelenítő rendszer által biztosított általános kivételkezelő kezeli.

A kivételeket a forrásból származtatott Exceptionosztályok jelölik. Ez az osztály azonosítja a kivétel típusát, és olyan tulajdonságokat tartalmaz, amelyek részletes információkat tartalmaznak a kivételről. A kivétel kioltásához létre kell hozni egy kivételből származtatott osztály egy példányát, opcionálisan konfigurálni kell a kivétel tulajdonságait, majd a kulcsszó használatával kell eldobni az throw objektumot. Például:

class CustomException : Exception
{
    public CustomException(string message)
    {
    }
}
private static void TestThrow()
{
    throw new CustomException("Custom exception in TestThrow()");
}

A kivételt követően a futtatókörnyezet ellenőrzi, hogy az aktuális utasítás egy try blokkon belül van-e. Ha igen, ellenőrzi a rendszer a catch blokkhoz tartozó összes try blokkot, hogy képesek-e észlelni a kivételt. Catch a blokkok általában kivételtípusokat határoznak meg; ha a catch blokk típusa megegyezik a kivétel típusával, vagy a kivétel alaposztálya, a catch blokk képes kezelni a metódust. Például:

try
{
    TestThrow();
}
catch (CustomException ex)
{
    System.Console.WriteLine(ex.ToString());
}

Ha a kivételt okozó utasítás nem egy try blokkon belül van, vagy ha az try azt tartalmazó blokk nem rendelkezik egyező catch blokktal, a futtatókörnyezet ellenőrzi a hívási metódust egy try utasítás és catch blokk esetében. A futtatókörnyezet tovább halad felfelé a hívásvermen, és egy kompatibilis catch blokkot keres. A blokk megtalálása és végrehajtása után a catch vezérlő a blokk utáni catch következő utasításnak lesz átadva.

Egy try utasítás több catch blokkot is tartalmazhat. A rendszer végrehajtja a kivételt kezelő első catch utasítást. A rendszer figyelmen kívül hagyja a következő catch utasításokat, még akkor is, ha kompatibilisek. A kivételkezelési blokkok sorrendje a legspecifikusabbtól (vagy a legtöbb származtatottól) a legkevésbé specifikusig. Például:

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");
        }
    }
}

A catch blokk végrehajtása előtt a futtatókörnyezet ellenőrzi finally a blokkokat. Finally a blokkok lehetővé teszik a programozó számára, hogy eltávolítson minden nem egyértelmű állapotot, amely egy megszakított try blokkból maradhat, vagy hogy külső erőforrásokat (például grafikus fogantyúkat, adatbázis-kapcsolatokat vagy fájlstreameket) szabadítson fel anélkül, hogy megvárná a kukagyűjtőt a futásidőben az objektumok véglegesítéséhez. Például:

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");
    }
}

Ha WriteByte() kivételt dobott, a második try blokkban lévő kód, amely megpróbálja újra megnyitni a fájlt, sikertelen lesz, ha file.Close() nincs meghívva, és a fájl zárolva marad. Mivel finally a blokkok akkor is végrehajtásra kerülnek, ha kivételt okoznak, az finally előző példában szereplő blokk lehetővé teszi a fájl helyes bezárását, és segít elkerülni a hibát.

Ha nem található kompatibilis catch blokk a hívásveremen egy kivétel kiírása után, a következő három dolog egyike következik be:

  • Ha a kivétel egy véglegesítőben van, a véglegesítő félbeszakad, és az alap véglegesítő, ha van ilyen, meghívásra kerül.
  • Ha a hívásverem statikus konstruktort vagy statikus mező inicializálót tartalmaz, akkor egy TypeInitializationException kivétel kerül kiváltásra, amelynek InnerException tulajdonságához az eredeti kivétel van rendelve.
  • Ha eléri a szál kezdetét, a szál leáll.