Skapa och generera 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 genereras sedan med instruktionenthroweller uttrycket. Körningen söker sedan efter den mest kompatibla 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 genererar 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 parametern InnerException som:

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

    Kommentar

    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 instruktionens throw punkt, 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 innehåller ArgumentException en egenskap med namnet ParamName som ska anges till namnet på argumentet som gjorde att undantaget utlöstes. I en egenskapsuppsättning ParamName ska 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 undvika när du utlöser undantag

I följande lista identifieras metoder som du kan undvika 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 genereras.
  • 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. Om du vill identifiera körningsfel under utvecklingsfasen använder du Felsöka Assert i stället.

Undantag i metoder för uppgiftsretur

Metoder som deklareras med async modifieraren har vissa särskilda överväganden när det gäller undantag. Undantag som genereras i en async metod lagras i den returnerade aktiviteten 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 eventuella motsvarande undantag, till exempel ArgumentException och ArgumentNullException, innan du anger de asynkrona delarna av dina metoder. De här verifieringsfelen bör alltså visas synkront innan arbetet påbörjas. Följande kodfragment visar ett exempel där undantagen visas synkront om undantagen ArgumentException utlöses, medan det InvalidOperationException skulle lagras i den returnerade aktiviteten.

// 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 utlösa en fördefinierad undantagsklass i System namnområdet (utom där tidigare antecknades) 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 Message egenskaperna 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 ToString() bör åsidosättas för att returnera den tillagda informationen.

Språkspecifikation för C#

Mer information finns i Undantag och Utkast-instruktioneni C#-språkspecifikationen. Språkspecifikationen är den slutgiltiga källan för C#-syntax och -användning.

Se även