Oefening: specifieke uitzonderingstypen vangen
Eerder in deze module hebt u geleerd dat de uitzonderingsobjecten die door uw C#-toepassing worden gevangen, exemplaren van een uitzonderingsklasse zijn. Over het algemeen zal catch uw code een van de volgende zijn:
- Een uitzonderingsobject dat een exemplaar van de
System.Exceptionbasisklasse is. - Een uitzonderingsobject dat een exemplaar is van een uitzonderingstype dat wordt overgenomen van de basisklasse. Bijvoorbeeld een exemplaar van de
InvalidCastExceptionklasse.
Uitzonderingseigenschappen onderzoeken
System.Exception is de basisklasse waaruit alle afgeleide uitzonderingstypen overnemen. Elk uitzonderingstype neemt over van de basisklasse via een specifieke klassehiërarchie. De klassehiërarchie voor de InvalidCastException is als volgt:
Object
Exception
SystemException
InvalidCastException
De meeste uitzonderingsklassen die overnemen van Exception , voegen geen extra functionaliteit toe; ze nemen gewoon over van Exception. Als u daarom de eigenschappen van de Exception klasse bekijkt, kunt u de meeste uitzonderingen begrijpen en hoe u een uitzondering in uw code kunt gebruiken.
Dit zijn de eigenschappen van de Exception klasse:
-
Gegevens: De
Dataeigenschap bevat willekeurige gegevens in sleutel-waardeparen. -
HelpLink: De
HelpLinkeigenschap kan worden gebruikt om een URL (of URN) op te slaan in een Help-bestand met uitgebreide informatie over de oorzaak van een uitzondering. -
HResult: De
HResulteigenschap kan worden gebruikt voor toegang tot een gecodeerde numerieke waarde die is toegewezen aan een specifieke uitzondering. -
InnerException: De
InnerExceptioneigenschap kan worden gebruikt om een reeks uitzonderingen te maken en te behouden tijdens het afhandelen van uitzonderingen. -
Bericht: De
Messageeigenschap bevat details over de oorzaak van een uitzondering. -
Bron: De
Sourceeigenschap kan worden gebruikt voor toegang tot de naam van de toepassing of het object dat de fout veroorzaakt. -
StackTrace: De
StackTraceeigenschap bevat een stack-trace die kan worden gebruikt om te bepalen waar een fout is opgetreden. -
TargetSite: De
TargetSiteeigenschap kan worden gebruikt om de methode op te halen waarmee de huidige uitzondering wordt gegenereerd.
Het is geen probleem als u zich een beetje overweldigd voelt door dit onderzoek naar uitzonderingseigenschappen, basisklassen en overname. Maak u geen zorgen, het vangen van uitzonderingen in uw code en het openen van de eigenschappen van een uitzondering zijn eenvoudiger dan uitleggen hoe uitzonderingen en uitzonderingseigenschappen werken.
Opmerking
In deze module richt u zich op het gebruik van de berichteigenschap van een uitzondering om de uitzondering te rapporteren in de gebruikersinterface van uw toepassing.
Toegang tot de eigenschappen van een uitzonderingsobject
Nu u uitzonderingsobjecten en hun eigenschappen begrijpt, is het tijd om te beginnen met coderen.
Werk uw Program.cs bestand als volgt bij:
try { Process1(); } catch { Console.WriteLine("An exception has occurred"); } Console.WriteLine("Exit program"); static void Process1() { try { WriteMessage(); } catch { Console.WriteLine("Exception caught in Process1"); } } static void WriteMessage() { double float1 = 3000.0; double float2 = 0.0; int number1 = 3000; int number2 = 0; Console.WriteLine(float1 / float2); Console.WriteLine(number1 / number2); }Neem even de tijd om de code te controleren.
Dit is dezelfde code die u in de vorige les hebt gezien (de oplossingscode voor de uitdagingsactiviteit). U weet dat er een uitzondering wordt gegenereerd tijdens de
WriteMessagemethode. U weet ook dat de uitzondering in deProcess1-methode wordt opgevangen. U gebruikt deze code om uitzonderingsobjecten en specifieke uitzonderingstypen te onderzoeken.Werk de
Process1methode als volgt bij:static void Process1() { try { WriteMessage(); } catch (Exception ex) { Console.WriteLine($"Exception caught in Process1: {ex.Message}"); } }Neem even de tijd om uw updates te bekijken.
U ziet dat uw bijgewerkte
catchclausal een instance van deExceptionklasse vangt in een object genaamdex. U ziet ook dat uwConsole.WriteLine()methodeexgebruikt om toegang te krijgen tot de eigenschap van hetMessageobject en het foutbericht op de console weer te geven.Hoewel de
catchcomponent zonder argumenten kan worden gebruikt, wordt deze benadering niet aanbevolen. Als u geen argument opgeeft, worden alle exceptietypen gevangen en kunt u ze niet onderscheiden.Over het algemeen moet u alleen de uitzonderingen opvangen die uw code kan herstellen. Daarom moet uw
catchcomponent een objectargument opgeven dat is afgeleid vanSystem.Exception. Het uitzonderingstype moet zo specifiek mogelijk zijn. Dit helpt voorkomen dat uitzonderingen onderschept worden die uw uitzonderingshandler niet kan oplossen. U werkt uw code bij om later in deze oefening een specifiek uitzonderingstype te vangen.In het menu Bestand selecteert u Opslaan.
Stel onderbrekingspunt in op de volgende coderegel:
Console.WriteLine($"Exception caught in Process1: {ex.Message}");Selecteer in het menu Uitvoeren de foutopsporing starten
Code-uitvoering moet worden onderbroken op het onderbrekingspunt.
Beweeg de muisaanwijzer over
ex.U ziet dat IntelliSense dezelfde uitzonderingseigenschappen weergeeft die u eerder hebt onderzocht.
Neem even de tijd om de informatie te bekijken die het uitzonderingsobject
exbeschrijft.U ziet dat de uitzondering een
System.DivideByZeroExceptionuitzonderingstype is en dat deMessageeigenschap is ingesteld opAttempted to divide by zero..U ziet dat de
StackTraceeigenschap de methode en het regelnummer rapporteert waar de fout is opgetreden, samen met de reeks methodeaanroepen (en regelnummers) die tot de fout hebben geleid.Op de Debug werkbalk selecteer Doorgaan.
Neem even de tijd om de console-uitvoer te bekijken.
U ziet dat de eigenschap van
Messagede uitzondering is opgenomen in de uitvoer die door uw toepassing wordt gegenereerd:∞ Exception caught in Process1: Attempted to divide by zero. Exit program
Een specifiek uitzonderingstype vangen
Nu u weet welk type uitzondering moet worden afhandeld, kunt u uw catch clausule bijwerken om dat specifieke uitzonderingstype af te handelen.
Werk de
Process1methode als volgt bij:static void Process1() { try { WriteMessage(); } catch (DivideByZeroException ex) { Console.WriteLine($"Exception caught in Process1: {ex.Message}"); } }Sla uw code op en start vervolgens een foutopsporingssessie.
U ziet dat uw bijgewerkte toepassing dezelfde berichten rapporteert aan de console.
Hoewel de gerapporteerde berichten hetzelfde zijn, is er een belangrijk verschil. Uw
Process1methode onderschept alleen uitzonderingen van het specifieke type waarop het is voorbereid om mee om te gaan.Als u een ander uitzonderingstype wilt genereren, werkt u de
WriteMessagemethode als volgt bij:static void WriteMessage() { double float1 = 3000.0; double float2 = 0.0; int number1 = 3000; int number2 = 0; byte smallNumber; Console.WriteLine(float1 / float2); // Console.WriteLine(number1 / number2); checked { smallNumber = (byte)number1; } }Let op het gebruik van de
checkedinstructie.Bij het uitvoeren van integrale typeberekeningen die de waarde van het ene integraaltype aan een ander integraaltype toewijzen, is het resultaat afhankelijk van de context van overloopcontrole. In een
checkedcontext slaagt de conversie als de bronwaarde binnen het bereik van het doeltype valt. Anders wordt eenOverflowExceptiongegooid. In een niet-gecontroleerd context slaagt de conversie altijd en gaat het als volgt:Als het brontype groter is dan het doeltype, wordt de bronwaarde afgekapt door de 'extra' belangrijkste bits te verwijderen. Het resultaat wordt vervolgens behandeld als een waarde van het doeltype.
Als het brontype kleiner is dan het doeltype, wordt de bronwaarde uitgebreid of nul uitgebreid, zodat deze van dezelfde grootte is als het doeltype. De tekenextensie wordt gebruikt als het brontype is ondertekend; zero-extension wordt gebruikt als het brontype niet is ondertekend. Het resultaat wordt vervolgens behandeld als een waarde van het doeltype.
Als het brontype dezelfde grootte heeft als het doeltype, wordt de bronwaarde beschouwd als een waarde van het doeltype.
Opmerking
Integrale typeberekeningen die zich niet in een
checkedcodeblok bevinden, worden behandeld alsof ze zich in eenuncheckedcodeblok bevinden.Sla uw code op en start vervolgens een foutopsporingssessie.
U ziet dat een nieuw uitzonderingstype wordt gedetecteerd door de
catchcomponent in de instructies op het hoogste niveau in plaats van binnen deProcess1methode.De toepassing drukt de volgende berichten af naar de console:
∞ An exception has occurred Exit programOpmerking
Het
catchblok inProcess1wordt niet uitgevoerd. Dit is het gewenste gedrag. Vang alleen de uitzonderingen op die uw code kan verwerken.
Meerdere uitzonderingen in een codeblok opvangen
Op dit moment vraagt u zich misschien af wat er gebeurt wanneer er meerdere uitzonderingen optreden in één codeblok. Registreert of behandelt uw code catch elke uitzondering zodra deze zich voordoet?
Werk de
WriteMessagemethode als volgt bij:static void WriteMessage() { double float1 = 3000.0; double float2 = 0.0; int number1 = 3000; int number2 = 0; byte smallNumber; Console.WriteLine(float1 / float2); Console.WriteLine(number1 / number2); checked { smallNumber = (byte)number1; } }Stel onderbrekingspunt in de
WriteMessage()methode in op de volgende coderegel:Console.WriteLine(float1 / float2);Sla uw code op en start vervolgens een foutopsporingssessie.
Doorloop uw code één regel tegelijk en u ziet wat er gebeurt nadat de code de eerste uitzondering heeft verwerkt.
Wanneer de eerste uitzondering optreedt, wordt het besturingselement doorgegeven aan de eerste
catchcomponent die de uitzondering kan verwerken. De code die de tweede uitzondering genereert, wordt nooit bereikt. Dit betekent dat sommige van uw code nooit wordt uitgevoerd. Dit kan leiden tot ernstige problemen.Neem even de tijd om na te gaan hoe u meerdere uitzonderingen kunt beheren en wanneer/waarom u mogelijk niet wilt dat uw code meerdere uitzonderingen beheert.
U hebt eerder in deze module geleerd dat uitzonderingen zo dicht mogelijk bij de locatie moeten worden opgevangen. Met dit in gedachten kunt u ervoor kiezen om de
WriteMessagemethode bij te werken om uitzonderingen te ondervangen met behulp van een eigentry-catchmethode. Voorbeeld:static void WriteMessage() { double float1 = 3000.0; double float2 = 0.0; int number1 = 3000; int number2 = 0; byte smallNumber; try { Console.WriteLine(float1 / float2); Console.WriteLine(number1 / number2); } catch (DivideByZeroException ex) { Console.WriteLine($"Exception caught in WriteMessage: {ex.Message}"); } checked { smallNumber = (byte)number1; } }U kunt ook de code verpakken die de
OverflowExceptionveroorzaakt in een afzonderlijketry-catchbinnen deWriteMessage()methode.checked { try { smallNumber = (byte)number1; } catch (OverflowException ex) { Console.WriteLine($"Exception caught in WriteMessage: {ex.Message}"); } }Onder welke omstandigheden zou het ongewenst zijn om volgende uitzonderingen af te handelen?
Houd rekening met het geval wanneer uw methode (of codeblok) een proces van twee delen voltooit. Stel dat het tweede deel van het proces afhankelijk is van het eerste deel dat is voltooid. Als het eerste deel van het proces niet kan worden voltooid, is het niet mogelijk om door te gaan naar het tweede deel van het proces. In dit geval is het vaak beter om de gebruiker een bericht te geven waarin de foutvoorwaarde wordt uitgelegd zonder het resterende gedeelte of de resterende delen van het grotere proces te proberen.
Afzonderlijke uitzonderingstypen in een codeblok vangen
Er zijn situaties waarin variaties in uw gegevens verschillende soorten uitzonderingen kunnen veroorzaken.
Wis uw onderbrekingspunten en vervang de inhoud van het Program.cs bestand door de volgende code:
// inputValues is used to store numeric values entered by a user string[] inputValues = new string[]{"three", "9999999999", "0", "2" }; foreach (string inputValue in inputValues) { int numValue = 0; try { numValue = int.Parse(inputValue); } catch (FormatException) { Console.WriteLine("Invalid readResult. Please enter a valid number."); } catch (OverflowException) { Console.WriteLine("The number you entered is too large or too small."); } catch(Exception ex) { Console.WriteLine(ex.Message); } }Neem even de tijd om deze code te controleren.
Eerst maakt de code een tekenreeksmatrix met de naam
inputValues. De gegevens in de matrix zijn bedoeld om de invoerwaarden weer te geven die zijn ingevoerd door een gebruiker die is geïnstrueerd om numerieke waarden in te voeren. Afhankelijk van de ingevoerde waarde kunnen verschillende uitzonderingstypen optreden.U ziet dat de code de
int.Parsemethode gebruikt om de invoerwaarden van de tekenreeks te converteren naar gehele getallen. Deint.Parsecode wordt in eentrycodeblok geplaatst.Stel een onderbrekingspunt in op de volgende coderegel:
int numValue = 0;Sla uw code op en start vervolgens een foutopsporingssessie.
Voer de code één regel tegelijk uit en merk op dat verschillende uitzonderingen worden opgevangen.
Samenvatting
Hier volgen enkele belangrijke dingen die u in deze les moet onthouden:
- De
catchcomponent moet worden geconfigureerd om een specifiek uitzonderingstype te vangen. Bijvoorbeeld hetDivideByZeroExceptionuitzonderingstype. - De eigenschappen van een uitzonderingsobject kunnen worden geopend binnen het
catchblok. U kunt bijvoorbeeld deMessageeigenschap gebruiken om de gebruiker van de toepassing te informeren over een probleem. - U kunt twee of meer
catchcomponenten opgeven wanneer u meer dan één uitzonderingstype moet vangen.