Megosztás a következőn keresztül:


Kivételek létrehozása és kizárása

A kivételek azt jelzik, hogy hiba történt a program futtatása során. A rendszer létrehoz egy hibát leíró kivételobjektumokat, majd az utasítással vagy kifejezéssel együtt dobja el azokatthrow. A futtatókörnyezet ezután megkeresi a legkompatibilisebb kivételkezelőt.

A programozóknak kivételeket kell kivenniük, ha az alábbi feltételek közül legalább egy teljesül:

  • A metódus nem tudja befejezni a definiált funkcióit. Ha például egy metódus paraméterének értéke érvénytelen:

    static void CopyObject(SampleClass original)
    {
        _ = original ?? throw new ArgumentException("Parameter cannot be null", nameof(original));
    }
    
  • Az objektum állapota alapján nem megfelelő hívás történik egy objektumra. Ilyen lehet például egy írásvédett fájlba való írás. Olyan esetekben, amikor egy objektumállapot nem engedélyezi a műveletet, az osztály származtatása InvalidOperationException alapján dobjon ki egy példányt vagy objektumot. Az alábbi kód egy objektumot dobó InvalidOperationException metódusra mutat be példát:

    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.
        }
    }
    
  • Ha egy metódus argumentuma kivételt okoz. Ebben az esetben az eredeti kivételt le kell kapni, és létre kell hozni egy példányt ArgumentException . Az eredeti kivételt a paraméter konstruktorának ArgumentExceptionInnerException kell átadni:

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

    Feljegyzés

    Az előző példa bemutatja, hogyan használhatja a tulajdonságot InnerException . Szándékosan leegyszerűsítik. A gyakorlatban a használat előtt ellenőriznie kell, hogy egy index tartományon belül van-e. Ezt a technikát akkor használhatja kivétel körbefuttatására, ha egy paraméter egy tagja olyan kivételt ad ki, amely nem várható a tag meghívása előtt.

A kivételek egy .StackTrace Ez a sztring tartalmazza az aktuális hívásverem metódusainak nevét, valamint azt a fájlnevet és sorszámot, ahol a kivételt az egyes metódusok kivétele eredményezte. A rendszer automatikusan létrehoz egy StackTrace objektumot a közös nyelvi futtatókörnyezet (CLR) által az throw utasítás pontjáról, így a kivételeket attól a ponttól kell elvetni, ahol a veremkövetésnek el kell kezdődnie.

Minden kivétel tartalmaz egy .Message Ezt a sztringet úgy kell beállítani, hogy elmagyarázza a kivétel okát. A biztonságra érzékeny információkat nem szabad az üzenet szövegébe helyezni. MessageEmellett tartalmaz egy nevű ParamName tulajdonságot is, ArgumentException amelyet a kivételt okozó argumentum nevére kell beállítani. A tulajdonságválasztóban ParamName a következő értékre kell állítani: value.

A nyilvános és védett metódusok kivételeket vetnek fel, ha nem tudják elvégezni a kívánt függvényeiket. A kidobott kivételosztály a rendelkezésre álló legspecifikusabb kivétel, amely megfelel a hibafeltételeknek. Ezeket a kivételeket az osztályfunkció részeként kell dokumentálni, és az eredeti osztály származtatott osztályainak vagy frissítéseinek ugyanazt a viselkedést kell megőrizniük a visszamenőleges kompatibilitás érdekében.

A kivételek eldobásakor elkerülendő dolgok

Az alábbi lista azonosítja a kivételekkel elkerülhető eljárásokat:

  • Ne használjon kivételeket egy program folyamatának módosításához a szokásos végrehajtás részeként. Használjon kivételeket a hibafeltételek jelentéséhez és kezeléséhez.
  • A kivételeket nem szabad visszatérési értékként vagy paraméterként visszaadni ahelyett, hogy kidobták volna őket.
  • Ne dobjonSystem.Exception, System.SystemExceptionSystem.NullReferenceExceptionne System.IndexOutOfRangeException vagy szándékosan a saját forráskódjából.
  • Ne hozzon létre kivételeket, amelyek hibakeresési módban, de kiadási módban nem hozhatók létre. A fejlesztési fázisban előforduló futásidejű hibák azonosításához használja inkább a Hibakeresési jogérvényesítést.

Kivételek a feladatvisszaküldött metódusokban

A módosítóval async deklarált metódusoknak különleges szempontokat kell figyelembe venniük a kivételek tekintetében. A metódusban async alkalmazott kivételek a visszaadott tevékenységben vannak tárolva, és csak akkor jelennek meg, ha például a feladatra várni kell. A tárolt kivételekről további információt az Aszinkron kivételek című témakörben talál.

Javasoljuk, hogy a metódusok aszinkron részeinek megadása előtt ellenőrizze az argumentumokat, és adjon meg minden megfelelő kivételt, például ArgumentException és ArgumentNullException. Vagyis ezeknek az érvényesítési kivételeknek szinkron módon kell megjelenniük a munka megkezdése előtt. Az alábbi kódrészlet egy példát mutat be, ahol a kivételek ki lettek dobva, a ArgumentException kivételek szinkron módon jelennek meg, míg a InvalidOperationException visszaadott feladat tárolja őket.

// 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();
    }
}

Kivételosztályok definiálása

A programok előre definiált kivételosztályt állíthatnak be a System névtérbe (kivéve, ha korábban feljegyezték), vagy létrehozhatják saját kivételosztályaikat a forrásból Exceptionvaló származtatással. A származtatott osztályoknak legalább három konstruktort kell meghatározniuk: egy paraméter nélküli konstruktort, egy olyant, amely beállítja az üzenettulajdonságot, és egyet, amely mind a tulajdonságokat, mind a MessageInnerException tulajdonságokat beállítja. Példa:

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

Új tulajdonságok hozzáadása a kivételosztályhoz, ha az általuk megadott adatok hasznosak a kivétel feloldásához. Ha új tulajdonságokat ad hozzá a származtatott kivételosztályhoz, ToString() felül kell bírálni a hozzáadott adatok visszaadásához.

C# nyelvspecifikáció

További információ: Kivételek és A dobás utasítás a C# nyelvi specifikációjában. A nyelvi specifikáció a C#-szintaxis és -használat végleges forrása.

Lásd még