Øvelse – fange bestemte undtagelsestyper

Fuldført

Tidligere i dette modul har du lært, at de undtagelsesobjekter, der er fanget af dit C#-program, er forekomster af en undtagelsesklasse. Generelt vil catch din kode være en af følgende:

  • Et undtagelsesobjekt, der er en forekomst af System.Exception basisklassen.
  • Et undtagelsesobjekt, der er en forekomst af en undtagelsestype, der nedarver fra basisklassen. Det kan f.eks. være en forekomst af InvalidCastException klassen.

Undersøg undtagelsesegenskaber

System.Exception er den basisklasse, som alle afledte undtagelsestyper arver fra. Hver undtagelsestype nedarver fra basisklassen via et bestemt klassehierarki. Klassehierarkiet for InvalidCastException er f.eks. som følger:

Object
    Exception
        SystemException
            InvalidCastException

De fleste af de undtagelsesklasser, der arver fra Exception , tilføjer ikke yderligere funktioner. De nedarver simpelthen fra Exception. Hvis du undersøger egenskaberne for Exception klassen, kan du derfor forstå de fleste undtagelser, og hvordan du kan bruge en undtagelse i din kode.

Her er egenskaberne for Exception klassen:

  • Data: Egenskaben Data indeholder vilkårlige data i nøgleværdipar.
  • HelpLink: Egenskaben HelpLink kan bruges til at indeholde en URL-adresse (eller URN) til en Hjælp-fil, der indeholder omfattende oplysninger om årsagen til en undtagelse.
  • HResult: Egenskaben HResult kan bruges til at få adgang til en kodet numerisk værdi, der er tildelt til en bestemt undtagelse.
  • InnerException: Egenskaben InnerException kan bruges til at oprette og bevare en række undtagelser under håndtering af undtagelser.
  • Meddelelse: Egenskaben Message indeholder oplysninger om årsagen til en undtagelse.
  • Kilde: Egenskaben Source kan bruges til at få adgang til navnet på det program eller det objekt, der forårsager fejlen.
  • StackTrace: Egenskaben StackTrace indeholder en staksporing, der kan bruges til at bestemme, hvor der opstod en fejl.
  • TargetSite: Egenskaben TargetSite kan bruges til at hente den metode, der udløser den aktuelle undtagelse.

Det er okay, hvis du føler dig lidt overvældet af denne undersøgelse af undtagelsesegenskaber, basisklasser og arv. Bare rolig, det er nemmere at fange undtagelser i din kode og få adgang til en undtagelses egenskaber end at forklare, hvordan undtagelser og undtagelsesegenskaber fungerer.

Seddel

I dette modul skal du fokusere på at bruge en undtagelses meddelelsesegenskab til at rapportere undtagelsen i programmets brugergrænseflade.

Få adgang til egenskaberne for et undtagelsesobjekt

Nu, hvor du forstår undtagelsesobjekter og deres egenskaber, er det tid til at begynde at kode.

  1. Opdater din Program.cs-fil på følgende måde:

    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. Brug et øjeblik på at gennemse koden.

    Dette er den samme kode, som du så i det forrige undermodul (løsningskoden for udfordringsaktiviteten). Du ved, at der udløses en undtagelse under WriteMessage metoden . Du ved også, at undtagelsen er fanget i Process1 metoden . Du skal bruge denne kode til at undersøge undtagelsesobjekter og specifikke undtagelsestyper.

  3. Opdater metoden Process1 på følgende måde:

    static void Process1()
    {
        try
        {
            WriteMessage();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Exception caught in Process1: {ex.Message}");
        }
    }
    
  4. Brug et øjeblik på at undersøge dine opdateringer.

    Bemærk, at den opdaterede catch delsætning fanger en forekomst af Exception klassen i et objekt med navnet ex. Bemærk også, at din Console.WriteLine() metode bruger ex til at få adgang til objektets Message egenskab og vise fejlmeddelelsen i konsollen.

    Selvom delsætningen catch kan bruges uden argumenter, anbefales denne fremgangsmåde ikke. Hvis du ikke angiver et argument, registreres alle undtagelsestyper, og du kan ikke afgrænse mellem dem.

    Generelt bør du kun fange de undtagelser, som din kode ved, hvordan du gendanner fra. Derfor skal din catch delsætning angive et objektargument, der er afledt af System.Exception. Undtagelsestypen skal være så specifik som muligt. Dette hjælper med at undgå at fange undtagelser, som din undtagelseshandler ikke kan løse. Du skal opdatere din kode for at fange en bestemt undtagelsestype senere i denne øvelse.

  5. Vælg Gemi menuen Filer .

  6. Angiv pausepunkt på følgende kodelinje:

    Console.WriteLine($"Exception caught in Process1: {ex.Message}");
    
  7. Vælg Start fejlfinding i menuen Kør

    Kodeudførelsen skal afbrydes midlertidigt ved pausepunktet.

  8. Hold musemarkøren over ex.

    Bemærk, at IntelliSense viser de samme undtagelsesegenskaber, som du undersøgte tidligere.

  9. Brug et minut på at undersøge de oplysninger, der beskriver undtagelsesobjektet ex.

    Bemærk, at undtagelsen er en System.DivideByZeroException undtagelsestype, og at egenskaben Message er angivet til Attempted to divide by zero..

    Bemærk, at StackTrace egenskaben rapporterer metoden og linjenummeret, hvor fejlen opstod, sammen med sekvensen af metodekald (og linjenumre), der førte til fejlen.

  10. Vælg Fortsætpå værktøjslinjen Fejlfinding.

  11. Brug et minut på at undersøge konsoloutputtet.

    Bemærk, at undtagelsens Message egenskab er inkluderet i det output, der genereres af dit program:

    ∞
    Exception caught in Process1: Attempted to divide by zero.
    Exit program
    

Fange en bestemt undtagelsestype

Nu, hvor du ved, hvilken undtagelsestype der skal registreres, kan du opdatere din catch delsætning for at håndtere den specifikke undtagelsestype.

  1. Opdater metoden Process1 på følgende måde:

    static void Process1()
    {
        try
        {
            WriteMessage();
        }
        catch (DivideByZeroException ex)
        {
            Console.WriteLine($"Exception caught in Process1: {ex.Message}");
        }
    }
    
  2. Gem din kode, og start derefter en fejlfindingssession.

  3. Bemærk, at dit opdaterede program rapporterer de samme meddelelser til konsollen.

    Selvom de rapporterede meddelelser er de samme, er der en vigtig forskel. Din Process1 metode fanger kun undtagelser af den specifikke type, den er klar til at håndtere.

  4. Hvis du vil generere en anden undtagelsestype, skal du WriteMessage opdatere metoden på følgende måde:

    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. Bemærk brugen af sætningen checked .

    Når du udfører beregninger af integraltyper, der tildeler værdien af én integraltype til en anden integraltype, afhænger resultatet af konteksten for kontrol af overløb. I en checked kontekst lykkes konverteringen, hvis kildeværdien er inden for intervallet for destinationstypen. Ellers udløses en OverflowException. I en kontekst, der ikke er markeret, lykkes konverteringen altid og fortsætter på følgende måde:

    • Hvis kildetypen er større end destinationstypen, afkortes kildeværdien ved at fjerne dens "ekstra" vigtigste bit. Resultatet behandles derefter som en værdi af destinationstypen.

    • Hvis kildetypen er mindre end destinationstypen, er kildeværdien enten sign-extended eller zero-extended, så den har samme størrelse som destinationstypen. Sign-extension bruges, hvis kildetypen er signeret. zero-extension bruges, hvis kildetypen ikke er signeret. Resultatet behandles derefter som en værdi af destinationstypen.

    • Hvis kildetypen har samme størrelse som destinationstypen, behandles kildeværdien som en værdi af destinationstypen.

    Seddel

    Beregninger af integraltyper, der ikke findes i en checked kodeblok, behandles, som om de er inde i en unchecked kodeblok.

  6. Gem din kode, og start derefter en fejlfindingssession.

  7. Bemærk, at en ny undtagelsestype fanges af delsætningen catch i sætningerne på øverste niveau i stedet for i Process1 metoden .

    Programmet udskriver følgende meddelelser i konsollen:

    ∞
    An exception has occurred
    Exit program
    

    Seddel

    Blokken catch i Process1 udføres ikke. Dette er den ønskede funktionsmåde. Du skal kun registrere de undtagelser, som din kode er klar til at håndtere.

Fange flere undtagelser i en kodeblok

På dette tidspunkt undrer du dig måske over, hvad der sker, når der opstår flere undtagelser i en enkelt kodeblok. Vil din kode catch hver undtagelse, som de opstår?

  1. Opdater metoden WriteMessage på følgende måde:

    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. Angiv pausepunkt i metoden WriteMessage() på følgende kodelinje:

    Console.WriteLine(float1 / float2);
    
  3. Gem din kode, og start derefter en fejlfindingssession.

  4. Gennemgå din kode én linje ad gangen, og læg mærke til, hvad der sker, når din kode håndterer den første undtagelse.

    Når den første undtagelse opstår, overføres kontrolelementet til den første catch delsætning, der kan håndtere undtagelsen. Den kode, der genererer den anden undtagelse, nås aldrig. Det betyder, at noget af din kode aldrig udføres. Dette kan føre til alvorlige problemer.

  5. Brug et øjeblik på at overveje, hvordan du kan administrere flere undtagelser, og hvornår/hvorfor du ikke ønsker, at din kode skal administrere flere undtagelser.

    Du har tidligere i dette modul lært, at undtagelser skal fanges så tæt på, hvor de forekommer som muligt. Med dette in mente kan du vælge at opdatere WriteMessage metoden for at fange undtagelser ved hjælp af sin egen try-catch. For eksempel:

    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;
        }
    }
    

    Du kan også ombryde den kode, der forårsager OverflowException i en separat try-catch i WriteMessage() metoden .

    checked
    {
        try
        {
            smallNumber = (byte)number1;
        }
        catch (OverflowException ex)
        {
            Console.WriteLine($"Exception caught in WriteMessage: {ex.Message}");
        }  
    }
    
  6. Under hvilke betingelser ville det være uønsket at fange efterfølgende undtagelser?

    Overvej det, når din metode (eller kodeblok) fuldfører en todelt proces. Antag, at den anden del af processen er afhængig af, at den første del fuldføres. Hvis den første del af processen ikke kan fuldføres, er der ingen grund til at fortsætte til anden del af processen. I dette tilfælde er det ofte bedre at præsentere brugeren for en meddelelse, der forklarer fejlbetingelsen uden at forsøge den resterende del af eller dele af den større proces.

Fange separate undtagelsestyper i en kodeblok

Der er tidspunkter, hvor variationer i dine data kan medføre forskellige typer undtagelser.

  1. Ryd dine pausepunkter, og erstat derefter indholdet af din Program.cs fil med følgende kode:

    // 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. Brug et øjeblik på at gennemse denne kode.

    Først opretter koden en strengmatrix med navnet inputValues. Dataene i matrixen er beregnet til at repræsentere de inputværdier, der er angivet af en bruger, som blev bedt om at angive numeriske værdier. Afhængigt af den angivne værdi kan der forekomme forskellige undtagelsestyper.

    Bemærk, at koden bruger int.Parse metoden til at konvertere strengværdierne "input" til heltal. Koden int.Parse placeres i en try kodeblok.

  3. Angiv et pausepunkt på følgende kodelinje:

    int numValue = 0;
    
  4. Gem din kode, og start derefter en fejlfindingssession.

  5. Gennemgå koden én linje ad gangen, og bemærk, at der registreres forskellige undtagelsestyper.

Resumé

Her er et par vigtige ting, du skal huske fra dette undermodul:

  • Delsætningen catch skal konfigureres til at fange en bestemt undtagelsestype. Undtagelsestypen DivideByZeroException .
  • Der er adgang til egenskaberne for et undtagelsesobjekt i catch blokken. Du kan f.eks. bruge egenskaben Message til at informere programbrugeren om et problem.
  • Du kan angive to eller flere catch delsætninger, når du har brug for at fange mere end én undtagelsestype.