Onderzoeken hoe u uitzonderingen maakt en genereert in C#
- 16 minuten
.NET biedt een hiërarchie van uitzonderingsklassen die zijn afgeleid van de System.Exception basisklasse. C#-toepassingen kunnen uitzonderingen van elk uitzonderingstype maken en genereren. Ontwikkelaars kunnen uitzonderingsobjecten ook aanpassen met toepassingsspecifieke informatie door eigenschapswaarden toe te wijzen.
Opmerking
Deze module is gericht op het maken en genereren van uitzonderingen en het aanpassen van uitzonderingsobjecten. Het maken van aangepaste uitzonderingsklassen valt buiten het bereik van deze module.
Een uitzonderingsobject maken
Het maken en genereren van uitzonderingen vanuit uw code is een belangrijk aspect van C#-programmering. De mogelijkheid om een uitzondering te genereren als reactie op een specifieke voorwaarde, probleem of fout helpt u om de stabiliteit van uw toepassing te garanderen.
Het uitzonderingstype dat u maakt, is afhankelijk van het coderingsprobleem en moet zo dicht mogelijk overeenkomen met het beoogde doel van de uitzondering.
Stel dat u een methode maakt met de naam GraphData die gegevensanalyse uitvoert. De methode ontvangt een gegevensmatrix als invoerparameter. De methode verwacht dat de invoergegevens zich in een bepaald bereik bevindt. Als de methode gegevens ontvangt die buiten het verwachte bereik liggen, wordt er een uitzondering van het type ArgumentExceptiongemaakt en gegenereerd. De uitzondering wordt ergens in de aanroepstack verwerkt door de code die verantwoordelijk is voor het leveren van de gegevens.
Hier volgen enkele veelvoorkomende uitzonderingstypen die u kunt gebruiken bij het maken van een uitzondering:
-
ArgumentExceptionofArgumentNullException: gebruik deze uitzonderingstypen wanneer een methode of constructor wordt aangeroepen met een ongeldige argumentwaarde of null-verwijzing. -
InvalidOperationException: Gebruik dit uitzonderingstype wanneer de operationele voorwaarden van een methode geen ondersteuning bieden voor de geslaagde voltooiing van een bepaalde methode-aanroep. -
NotSupportedException: Gebruik dit uitzonderingstype wanneer een bewerking of functie niet wordt ondersteund. -
IOException: Gebruik dit uitzonderingstype wanneer een invoer-/uitvoerbewerking mislukt. -
FormatException: Gebruik dit uitzonderingstype wanneer de notatie van een tekenreeks of gegevens onjuist is.
Het new trefwoord wordt gebruikt om een exemplaar van een uitzondering te maken. U kunt bijvoorbeeld als volgt een exemplaar van het ArgumentException uitzonderingstype maken:
ArgumentException invalidArgumentException = new ArgumentException();
Aangepaste uitzonderingen configureren en opwerpen
Het proces voor het genereren van een uitzonderingsobject omvat het maken van een exemplaar van een uitzonderingsklasse, eventueel het configureren van eigenschappen van de uitzondering en het genereren van het object met behulp van het throw trefwoord.
Het is vaak handig om een uitzondering aan te passen met contextuele informatie voordat deze wordt gegenereerd. U kunt toepassingsspecifieke informatie opgeven binnen een uitzonderingsobject door de eigenschappen ervan te configureren. De volgende code maakt bijvoorbeeld een uitzonderingsobject met de naam invalidArgumentException met een aangepaste Message eigenschap en genereert vervolgens de uitzondering:
ArgumentException invalidArgumentException = new ArgumentException("ArgumentException: The 'GraphData' method received data outside the expected range.");
throw invalidArgumentException;
Opmerking
De Message eigenschap van een uitzondering is alleen-lezen. Daarom moet een aangepaste Message eigenschap worden ingesteld bij het instantiëren van het object.
Bij het aanpassen van een uitzonderingsobject is het belangrijk dat u duidelijke foutberichten opgeeft waarin het probleem wordt beschreven en hoe u dit kunt oplossen. U kunt ook aanvullende informatie opnemen, zoals stacktraceringen en foutcodes, zodat gebruikers het probleem kunnen oplossen.
Een uitzonderingsobject kan ook rechtstreeks binnen een throw instructie worden gemaakt. Voorbeeld:
throw new FormatException("FormatException: Calculations in process XYZ have been cancelled due to invalid data format.");
Enkele overwegingen waarmee u rekening moet houden bij het genereren van een uitzondering zijn:
- De
Messageeigenschap moet de reden voor de uitzondering uitleggen. Informatie die gevoelig is of die een beveiligingsprobleem vertegenwoordigt, mag echter niet in de berichttekst worden geplaatst. - De
StackTraceeigenschap wordt vaak gebruikt om de oorsprong van de uitzondering bij te houden. Deze tekenreekseigenschap bevat de naam van de methoden op de huidige aanroepstack, samen met de bestandsnaam en het regelnummer in elke methode die is gekoppeld aan de uitzondering.StackTracewordt er automatisch een object gemaakt door de Common Language Runtime (CLR) vanaf het punt van dethrowinstructie. Uitzonderingen moeten worden opgeworpen vanaf het punt waar de stacktrace moet beginnen.
Wanneer een uitzondering te gooien
Methoden moeten een uitzondering genereren wanneer ze hun beoogde doel niet kunnen voltooien. De gegenereerde uitzondering moet zijn gebaseerd op de meest specifieke uitzondering die past bij de foutvoorwaarden.
Overweeg een scenario waarin een ontwikkelaar werkt aan een toepassing die een bedrijfsproces implementeert. Het bedrijfsproces is afhankelijk van gebruikersinvoer. Als de invoer niet overeenkomt met het verwachte gegevenstype, maakt en genereert de methode waarmee het bedrijfsproces wordt geïmplementeerd een uitzondering. Het uitzonderingsobject kan worden geconfigureerd met toepassingsspecifieke informatie in de eigenschapswaarden. In het volgende codevoorbeeld ziet u het scenario:
string[][] userEnteredValues = new string[][]
{
new string[] { "1", "two", "3"},
new string[] { "0", "1", "2"}
};
foreach (string[] userEntries in userEnteredValues)
{
try
{
BusinessProcess1(userEntries);
}
catch (Exception ex)
{
if (ex.StackTrace.Contains("BusinessProcess1") && (ex is FormatException))
{
Console.WriteLine(ex.Message);
}
}
}
static void BusinessProcess1(string[] userEntries)
{
int valueEntered;
foreach (string userValue in userEntries)
{
try
{
valueEntered = int.Parse(userValue);
// completes required calculations based on userValue
// ...
}
catch (FormatException)
{
FormatException invalidFormatException = new FormatException("FormatException: User input values in 'BusinessProcess1' must be valid integers");
throw invalidFormatException;
}
}
}
In dit codevoorbeeld roepen de instructies op het hoogste niveau de BusinessProcess1 methode aan, waarbij een tekenreeksmatrix wordt doorgegeven die door de gebruiker ingevoerde waarden bevat. In de BusinessProcess1 methode worden gebruikersinvoerwaarden verwacht die kunnen worden geconverteerd naar een geheel getal. Wanneer de methode gegevens met een ongeldige indeling tegenkomt, wordt er een exemplaar van het FormatException uitzonderingstype gemaakt met behulp van een aangepaste Message eigenschap. De methode genereert vervolgens de uitzondering. De uitzondering wordt gevangen in de topniveaustatements als een object met de naam ex. Eigenschappen van het ex object worden onderzocht voordat het uitzonderingsbericht voor de gebruiker wordt weergegeven. Eerst onderzoekt de code de StackTrace eigenschap om te zien of deze 'BusinessProcess1' bevat. Ten tweede is het uitzonderingsobject ex geverifieerd om van het type FormatExceptionte zijn.
Uitzonderingen opnieuw gooien
Naast het genereren van een nieuwe uitzondering kunt u met throw een uitzondering opnieuw opwerpen vanuit een catch codeblok. In dit geval throw wordt geen uitzonderingsoperand gebruikt.
catch (Exception ex)
{
// handle or partially handle the exception
// ...
// re-throw the original exception object for further handling down the call stack
throw;
}
Wanneer u een uitzondering opnieuw genereert, wordt het oorspronkelijke uitzonderingsobject gebruikt, zodat u geen informatie over de uitzondering kwijtraakt. Als u een nieuw uitzonderingsobject wilt maken waarmee de oorspronkelijke uitzondering wordt verpakt, kunt u de oorspronkelijke uitzondering als argument doorgeven aan de constructor van een nieuw uitzonderingsobject. Voorbeeld:
catch (Exception ex)
{
// handle or partially handle the exception
// ...
// create a new exception object that wraps the original exception
throw new ApplicationException("An error occurred", ex);
}
Houd rekening met de volgende updates voor het toepassingsscenario 'BusinessProcess1':
- De
BusinessProcess1methode is bijgewerkt met aanvullende informatie.BusinessProcess1ondervindt nu twee problemen en moet uitzonderingen genereren voor elk probleem. - De verklaringen op topniveau zijn bijgewerkt. Instructies op het hoogste niveau roepen nu de
OperatingProcedure1methode aan.OperatingProcedure1roeptBusinessProcess1aan binnen eentrycodeblok. - De
OperatingProcedure1methode kan een van de uitzonderingstypen verwerken en de andere gedeeltelijk verwerken. Zodra de gedeeltelijk verwerkte uitzondering is verwerkt, moetOperatingProcedure1de oorspronkelijke uitzondering opnieuw werpen.
In het volgende codevoorbeeld ziet u het bijgewerkte scenario:
try
{
OperatingProcedure1();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine("Exiting application.");
}
static void OperatingProcedure1()
{
string[][] userEnteredValues = new string[][]
{
new string[] { "1", "two", "3"},
new string[] { "0", "1", "2"}
};
foreach(string[] userEntries in userEnteredValues)
{
try
{
BusinessProcess1(userEntries);
}
catch (Exception ex)
{
if (ex.StackTrace.Contains("BusinessProcess1"))
{
if (ex is FormatException)
{
Console.WriteLine(ex.Message);
Console.WriteLine("Corrective action taken in OperatingProcedure1");
}
else if (ex is DivideByZeroException)
{
Console.WriteLine(ex.Message);
Console.WriteLine("Partial correction in OperatingProcedure1 - further action required");
// re-throw the original exception
throw;
}
else
{
// create a new exception object that wraps the original exception
throw new ApplicationException("An error occurred - ", ex);
}
}
}
}
}
static void BusinessProcess1(string[] userEntries)
{
int valueEntered;
foreach (string userValue in userEntries)
{
try
{
valueEntered = int.Parse(userValue);
checked
{
int calculatedValue = 4 / valueEntered;
}
}
catch (FormatException)
{
FormatException invalidFormatException = new FormatException("FormatException: User input values in 'BusinessProcess1' must be valid integers");
throw invalidFormatException;
}
catch (DivideByZeroException)
{
DivideByZeroException unexpectedDivideByZeroException = new DivideByZeroException("DivideByZeroException: Calculation in 'BusinessProcess1' encountered an unexpected divide by zero");
throw unexpectedDivideByZeroException;
}
}
}
De bijgewerkte voorbeeldcode produceert de volgende uitvoer:
FormatException: User input values in 'BusinessProcess1' must be valid integers
Corrective action taken in OperatingProcedure1
DivideByZeroException: Calculation in 'BusinessProcess1' encountered an unexpected divide by zero
Partial correction in OperatingProcedure1 - further action required
DivideByZeroException: Calculation in 'BusinessProcess1' encountered an unexpected divide by zero
Exiting application.
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.NullReferenceExceptionofSystem.IndexOutOfRangeExceptionniet opzettelijk uit uw eigen broncode. - Maak geen uitzonderingen die kunnen worden gegenereerd in de foutopsporingsmodus, maar niet in de releasemodus. Identificeer runtimefouten tijdens de ontwikkelingsfase door
Debug.Assertin plaats daarvan te gebruiken.
Opmerking
De Debug.Assert methode is een hulpprogramma voor het ondervangen van logische fouten tijdens de ontwikkeling. De methode werkt standaard Debug.Assert alleen in builds voor foutopsporing. U kunt in foutopsporingssessies gebruiken Debug.Assert om te controleren op een voorwaarde die nooit mag optreden. De methode gebruikt twee parameters: een Booleaanse voorwaarde om te controleren en een optioneel tekenreeksbericht om weer te geven als de voorwaarde is false.
Debug.Assert mag niet worden gebruikt in plaats van een uitzondering te genereren. Dit is een manier om uitzonderlijke situaties tijdens de normale uitvoering van uw code af te handelen. U dient Debug.Assert te gebruiken om fouten te onderscheppen die nooit mogen optreden, en uitzonderingen te gebruiken om fouten af te handelen die zich kunnen voordoen tijdens de normale uitvoering van uw programma.
Samenvatting
Hier volgen enkele belangrijke dingen die u in deze les moet onthouden:
- Wanneer u een uitzondering maakt en genereert, moet het uitzonderingstype zo dicht mogelijk overeenkomen met het beoogde doel van de uitzondering.
- Om
throween uitzondering te maken, maakt u een instantie van een klasse die van een uitzondering is afgeleid, configureert u de eigenschappen en gebruikt u vervolgens hetthrowtrefwoord. - Bij het maken van een uitzonderingsobject is het belangrijk dat u duidelijke foutberichten en aanvullende informatie opgeeft om gebruikers te helpen het probleem op te lossen.