Dela via


Skapa och kasta undantag

Undantag används för att indikera att ett fel har inträffat när programmet körs. Undantagsobjekt som beskriver ett fel skapas och kastas sedan med throw-instruktionen eller uttrycket. Programmet söker sedan efter den mest lämpliga undantagshanteraren.

Programmerare bör utlösa undantag när ett eller flera av följande villkor är uppfyllda:

  • Metoden kan inte slutföra sina definierade funktioner. Om en parameter till en metod till exempel har ett ogiltigt värde:

    static void CopyObject(SampleClass original)
    {
        _ = original ?? throw new ArgumentException("Parameter cannot be null", nameof(original));
    }
    
  • Ett olämpligt anrop till ett objekt görs baserat på objekttillståndet. Ett exempel kan vara att försöka skriva till en skrivskyddad fil. I fall där ett objekttillstånd inte tillåter en åtgärd utlöser du en instans av InvalidOperationException eller ett objekt baserat på en härledning av den här klassen. Följande kod är ett exempel på en metod som genererar ett 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.
        }
    }
    
  • När ett argument till en metod orsakar ett undantag. I det här fallet bör det ursprungliga undantaget fångas och en ArgumentException instans skapas. Det ursprungliga undantaget ska skickas till konstruktorn för ArgumentException som parametern InnerException:

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

    Anmärkning

    Föregående exempel visar hur du använder egenskapen InnerException. Det är avsiktligt förenklat. I praktiken bör du kontrollera att ett index ligger inom intervallet innan du använder det. Du kan använda den här metoden för att omsluta ett undantag när en medlem i en parameter genererar ett undantag som du inte kunde förutse innan du anropade medlemmen.

Undantag innehåller en egenskap med namnet StackTrace. Den här strängen innehåller namnet på metoderna i den aktuella anropsstacken, tillsammans med filnamnet och radnumret där undantaget utlöstes för varje metod. Ett StackTrace-objekt skapas automatiskt av CLR (Common Language Runtime) från punkten i throw-instruktionen, så att undantag måste genereras från den punkt där stackspårningen ska börja.

Alla undantag innehåller en egenskap med namnet Message. Den här strängen ska anges för att förklara orsaken till undantaget. Information som är känslig för säkerhet ska inte läggas till i meddelandetexten. Förutom Messageinnehåller ArgumentException en egenskap med namnet ParamName som ska anges till namnet på argumentet som gjorde att undantaget utlöstes. I en egenskapsuppsättning ska ParamName anges till value.

Offentliga och skyddade metoder utlöser undantag när de inte kan slutföra sina avsedda funktioner. Undantagsklassen som genereras är det mest specifika undantaget som passar felvillkoren. Dessa undantag bör dokumenteras som en del av klassfunktionerna, och härledda klasser eller uppdateringar av den ursprungliga klassen bör behålla samma beteende för bakåtkompatibilitet.

Saker att tänka på när du utlöser undantag

I följande lista identifieras metoder att tänka på när du utlöser undantag:

  • Använd inte undantag för att ändra flödet för ett program som en del av den vanliga körningen. Använd undantag för att rapportera och hantera feltillstånd.
  • Undantag ska inte returneras som ett returvärde eller en parameter i stället för att kastas.
  • Kasta inte System.Exception, System.SystemException, System.NullReferenceExceptioneller System.IndexOutOfRangeException avsiktligt från din egen källkod.
  • Skapa inte undantag som kan genereras i felsökningsläge men inte versionsläge. För att identifiera körningsfel under utvecklingsfasen använder du istället Debug.Assert.

Undantag i metoder för uppgiftsretur

Metoder som deklareras med async modifierare har vissa särskilda överväganden när det gäller undantag. Undantag som utlöses i en async-metod lagras i den returnerade uppgiften och visas inte förrän uppgiften, till exempel, väntar. Mer information om lagrade undantag finns i asynkrona undantag.

Vi rekommenderar att du validerar argument och utlöser motsvarande undantag, till exempel ArgumentException och ArgumentNullException, innan du anger de asynkrona delarna av metoderna. De här verifieringsfelen bör alltså visas synkront innan arbetet påbörjas. Följande kodfragment visar ett exempel där, när undantagen slängs, skulle ArgumentException-undantag uppstå synkront, medan InvalidOperationException skulle lagras i den returnerade uppgiften.

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

Definiera undantagsklasser

Program kan generera en fördefinierad undantagsklass i System-namnområdet (förutom där tidigare nämnts) eller skapa egna undantagsklasser genom att härleda från Exception. De härledda klasserna bör definiera minst tre konstruktorer: en parameterlös konstruktor, en som anger meddelandeegenskapen och en som anger både egenskaperna Message och InnerException. Till exempel:

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

Lägg till nya egenskaper i undantagsklassen när de data de tillhandahåller är användbara för att lösa undantaget. Om nya egenskaper läggs till i den härledda undantagsklassen bör ToString() åsidosättas för att returnera den tillagda informationen.

Språkspecifikation för C#

Mer information finns i Exceptions och The throw statement i C# Language Specification. Språkspecifikationen är den slutgiltiga källan för C#-syntax och -användning.

Se även