Oefening: specifieke uitzonderingstypen vangen

Voltooid

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.Exception basisklasse is.
  • Een uitzonderingsobject dat een exemplaar is van een uitzonderingstype dat wordt overgenomen van de basisklasse. Bijvoorbeeld een exemplaar van de InvalidCastException klasse.

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 Data eigenschap bevat willekeurige gegevens in sleutel-waardeparen.
  • HelpLink: De HelpLink eigenschap 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 HResult eigenschap kan worden gebruikt voor toegang tot een gecodeerde numerieke waarde die is toegewezen aan een specifieke uitzondering.
  • InnerException: De InnerException eigenschap kan worden gebruikt om een reeks uitzonderingen te maken en te behouden tijdens het afhandelen van uitzonderingen.
  • Bericht: De Message eigenschap bevat details over de oorzaak van een uitzondering.
  • Bron: De Source eigenschap kan worden gebruikt voor toegang tot de naam van de toepassing of het object dat de fout veroorzaakt.
  • StackTrace: De StackTrace eigenschap bevat een stack-trace die kan worden gebruikt om te bepalen waar een fout is opgetreden.
  • TargetSite: De TargetSite eigenschap 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.

  1. 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);
    }
    
  2. 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 WriteMessage methode. U weet ook dat de uitzondering in de Process1-methode wordt opgevangen. U gebruikt deze code om uitzonderingsobjecten en specifieke uitzonderingstypen te onderzoeken.

  3. Werk de Process1 methode als volgt bij:

    static void Process1()
    {
        try
        {
            WriteMessage();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Exception caught in Process1: {ex.Message}");
        }
    }
    
  4. Neem even de tijd om uw updates te bekijken.

    U ziet dat uw bijgewerkte catch clausal een instance van de Exception klasse vangt in een object genaamd ex. U ziet ook dat uw Console.WriteLine() methode ex gebruikt om toegang te krijgen tot de eigenschap van het Message object en het foutbericht op de console weer te geven.

    Hoewel de catch component 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 catch component een objectargument opgeven dat is afgeleid van System.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.

  5. In het menu Bestand selecteert u Opslaan.

  6. Stel onderbrekingspunt in op de volgende coderegel:

    Console.WriteLine($"Exception caught in Process1: {ex.Message}");
    
  7. Selecteer in het menu Uitvoeren de foutopsporing starten

    Code-uitvoering moet worden onderbroken op het onderbrekingspunt.

  8. Beweeg de muisaanwijzer over ex.

    U ziet dat IntelliSense dezelfde uitzonderingseigenschappen weergeeft die u eerder hebt onderzocht.

  9. Neem even de tijd om de informatie te bekijken die het uitzonderingsobject exbeschrijft.

    U ziet dat de uitzondering een System.DivideByZeroException uitzonderingstype is en dat de Message eigenschap is ingesteld op Attempted to divide by zero..

    U ziet dat de StackTrace eigenschap de methode en het regelnummer rapporteert waar de fout is opgetreden, samen met de reeks methodeaanroepen (en regelnummers) die tot de fout hebben geleid.

  10. Op de Debug werkbalk selecteer Doorgaan.

  11. Neem even de tijd om de console-uitvoer te bekijken.

    U ziet dat de eigenschap van Message de 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.

  1. Werk de Process1 methode als volgt bij:

    static void Process1()
    {
        try
        {
            WriteMessage();
        }
        catch (DivideByZeroException ex)
        {
            Console.WriteLine($"Exception caught in Process1: {ex.Message}");
        }
    }
    
  2. Sla uw code op en start vervolgens een foutopsporingssessie.

  3. U ziet dat uw bijgewerkte toepassing dezelfde berichten rapporteert aan de console.

    Hoewel de gerapporteerde berichten hetzelfde zijn, is er een belangrijk verschil. Uw Process1 methode onderschept alleen uitzonderingen van het specifieke type waarop het is voorbereid om mee om te gaan.

  4. Als u een ander uitzonderingstype wilt genereren, werkt u de WriteMessage methode 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;
        }
    }
    
  5. Let op het gebruik van de checked instructie.

    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 checked context slaagt de conversie als de bronwaarde binnen het bereik van het doeltype valt. Anders wordt een OverflowException gegooid. 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 checked codeblok bevinden, worden behandeld alsof ze zich in een unchecked codeblok bevinden.

  6. Sla uw code op en start vervolgens een foutopsporingssessie.

  7. U ziet dat een nieuw uitzonderingstype wordt gedetecteerd door de catch component in de instructies op het hoogste niveau in plaats van binnen de Process1 methode.

    De toepassing drukt de volgende berichten af naar de console:

    ∞
    An exception has occurred
    Exit program
    

    Opmerking

    Het catch blok in Process1 wordt 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?

  1. Werk de WriteMessage methode 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;
        }
    }
    
  2. Stel onderbrekingspunt in de WriteMessage() methode in op de volgende coderegel:

    Console.WriteLine(float1 / float2);
    
  3. Sla uw code op en start vervolgens een foutopsporingssessie.

  4. 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 catch component 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.

  5. 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 WriteMessage methode bij te werken om uitzonderingen te ondervangen met behulp van een eigen try-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 OverflowException veroorzaakt in een afzonderlijke try-catch binnen de WriteMessage() methode.

    checked
    {
        try
        {
            smallNumber = (byte)number1;
        }
        catch (OverflowException ex)
        {
            Console.WriteLine($"Exception caught in WriteMessage: {ex.Message}");
        }  
    }
    
  6. 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.

  1. 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);
        }
    }
    
  2. 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.Parse methode gebruikt om de invoerwaarden van de tekenreeks te converteren naar gehele getallen. De int.Parse code wordt in een try codeblok geplaatst.

  3. Stel een onderbrekingspunt in op de volgende coderegel:

    int numValue = 0;
    
  4. Sla uw code op en start vervolgens een foutopsporingssessie.

  5. 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 catch component moet worden geconfigureerd om een specifiek uitzonderingstype te vangen. Bijvoorbeeld het DivideByZeroException uitzonderingstype.
  • De eigenschappen van een uitzonderingsobject kunnen worden geopend binnen het catch blok. U kunt bijvoorbeeld de Message eigenschap gebruiken om de gebruiker van de toepassing te informeren over een probleem.
  • U kunt twee of meer catch componenten opgeven wanneer u meer dan één uitzonderingstype moet vangen.