Uitzonderingen maken en opwerpen
Uitzonderingen worden gebruikt om aan te geven dat er een fout is opgetreden tijdens het uitvoeren van het programma. Uitzonderingsobjecten die een fout beschrijven, worden gemaakt en vervolgens opgeworpen met de throw
-instructie of expressie. De runtime zoekt vervolgens naar de meest compatibele uitzonderingshandler.
Programmeurs moeten uitzonderingen genereren wanneer aan een of meer van de volgende voorwaarden wordt voldaan:
De methode kan de gedefinieerde functionaliteit niet voltooien. Als een parameter voor een methode bijvoorbeeld een ongeldige waarde heeft:
static void CopyObject(SampleClass original) { _ = original ?? throw new ArgumentException("Parameter cannot be null", nameof(original)); }
Er wordt een ongepaste aanroep van een object gemaakt op basis van de objectstatus. Een voorbeeld hiervan is proberen te schrijven naar een alleen-lezen bestand. In gevallen waarin een objectstatus geen bewerking toestaat, genereert u een exemplaar van InvalidOperationException of een object op basis van een afleiding van deze klasse. De volgende code is een voorbeeld van een methode waarmee een InvalidOperationException-object wordt gegenereerd:
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. } }
Wanneer een argument voor een methode een uitzondering veroorzaakt. In dit geval moet de oorspronkelijke uitzondering worden opgevangen en moet er een ArgumentException exemplaar worden gemaakt. De oorspronkelijke uitzondering moet worden doorgegeven aan de constructor van de ArgumentException als de parameter 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); } }
Notitie
In het voorgaande voorbeeld ziet u hoe u de eigenschap
InnerException
gebruikt. Het is opzettelijk vereenvoudigd. In de praktijk moet u controleren of een index zich in het bereik bevindt voordat u deze gebruikt. U kunt deze techniek gebruiken om een uitzondering te verpakken wanneer een lid van een parameter een uitzondering genereert die u niet kon verwachten voordat u het lid aanroept.
Uitzonderingen bevatten een eigenschap met de naam StackTrace. Deze tekenreeks bevat de naam van de methoden op de huidige aanroepstack, samen met de bestandsnaam en het regelnummer waar de uitzondering voor elke methode is gegenereerd. Een StackTrace-object wordt automatisch gemaakt door de Common Language Runtime (CLR) vanaf het punt van de throw
-instructie, zodat uitzonderingen moeten worden gegenereerd vanaf het punt waar de stack-trace moet beginnen.
Alle uitzonderingen bevatten een eigenschap met de naam Message. Deze tekenreeks moet worden ingesteld om de reden voor de uitzondering toe te lichten. Informatie die gevoelig is voor beveiliging, mag niet in de berichttekst worden geplaatst. Naast Messagebevat ArgumentException een eigenschap met de naam ParamName die moet worden ingesteld op de naam van het argument waardoor de uitzondering werd gegenereerd. In een eigenschapssetter moet ParamName worden ingesteld op value
.
Openbare en beveiligde methoden genereren uitzonderingen wanneer ze hun beoogde functies niet kunnen voltooien. De gegenereerde uitzonderingsklasse is de meest specifieke uitzondering die past bij de foutvoorwaarden. Deze uitzonderingen moeten worden gedocumenteerd als onderdeel van de klassefunctionaliteit en afgeleide klassen of updates van de oorspronkelijke klasse moeten hetzelfde gedrag behouden voor achterwaartse compatibiliteit.
Dingen die moeten worden vermeden bij het genereren van uitzonderingen
De volgende lijst identificeert procedures die moeten worden vermeden bij het genereren van uitzonderingen:
- Gebruik geen uitzonderingen om de stroom van een programma te wijzigen als onderdeel van gewone uitvoering. Gebruik uitzonderingen om foutvoorwaarden te rapporteren en af te handelen.
- Uitzonderingen mogen niet worden geretourneerd als een retourwaarde of parameter in plaats van te worden gegooid.
- Gooi System.Exception, System.SystemException, System.NullReferenceExceptionof System.IndexOutOfRangeException niet opzettelijk uit uw eigen broncode.
- Maak geen uitzonderingen die kunnen worden gegenereerd in de foutopsporingsmodus, maar niet in de releasemodus. Als u runtimefouten tijdens de ontwikkelingsfase wilt identificeren, gebruikt u In plaats daarvan Debug Assert.
Uitzonderingen in methoden voor het retourneren van taken
Methoden die zijn gedeclareerd met de async
modifier hebben een aantal speciale overwegingen als het gaat om uitzonderingen. Uitzonderingen die worden gegenereerd in een async
-methode worden opgeslagen in de geretourneerde taak en treden pas naar voren wanneer de taak bijvoorbeeld wordt afgewacht. Zie Asynchrone uitzonderingenvoor meer informatie over opgeslagen uitzonderingen.
U wordt aangeraden argumenten te valideren en eventuele bijbehorende uitzonderingen, zoals ArgumentException en ArgumentNullException, te genereren voordat u de asynchrone onderdelen van uw methoden invoert. Dat wil gezegd: deze validatieuitzondering moet synchroon ontstaan voordat het werk begint. In het volgende codefragment ziet u een voorbeeld waarin, als de uitzonderingen worden gegenereerd, de ArgumentException uitzonderingen synchroon worden weergegeven, terwijl de InvalidOperationException worden opgeslagen in de geretourneerde taak.
// 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();
}
}
Uitzonderingsklassen definiëren
Programma's kunnen een vooraf gedefinieerde uitzonderingsklasse genereren in de System naamruimte (behalve waar eerder vermeld) of hun eigen uitzonderingsklassen maken door deze te afleiden van Exception. De afgeleide klassen moeten ten minste drie constructors definiëren: één parameterloze constructor, één die de berichteigenschap instelt en één waarmee zowel de eigenschappen Message als InnerException worden ingesteld. Bijvoorbeeld:
[Serializable]
public class InvalidDepartmentException : Exception
{
public InvalidDepartmentException() : base() { }
public InvalidDepartmentException(string message) : base(message) { }
public InvalidDepartmentException(string message, Exception inner) : base(message, inner) { }
}
Voeg nieuwe eigenschappen toe aan de uitzonderingsklasse wanneer de gegevens die ze leveren nuttig zijn om de uitzondering op te lossen. Als er nieuwe eigenschappen worden toegevoegd aan de afgeleide uitzonderingsklasse, moet ToString()
worden overschreven om de toegevoegde informatie te retourneren.
C#-taalspecificatie
Zie Uitzonderingen en De throw instructie in de C# Taal Specificatievoor meer informatie. De taalspecificatie is de definitieve bron voor de C#-syntaxis en het gebruik.