Exercice - Intercepter des types d’exceptions spécifiques

Terminé

Plus haut dans ce module, vous avez appris que les objets d’exception interceptés par votre application C# sont des instances d’une classe d’exception. En règle générale, votre code effectuera un catch sur l’un des éléments suivants :

  • Objet d’exception qui est une instance de la System.Exception classe de base.
  • Objet d’exception qui est une instance d’un type d’exception qui hérite de la classe de base. Par exemple, une instance de la InvalidCastException classe.

Examiner les propriétés d’exception

System.Exception est la classe de base dont héritent tous les types d’exceptions dérivés. Chaque type d’exception hérite de la classe de base via une hiérarchie de classes spécifique. Par exemple, la hiérarchie de classes pour la InvalidCastException classe est la suivante :

Object
    Exception
        SystemException
            InvalidCastException

La plupart des classes d'exception qui héritent de Exception n'ajoutent pas de fonctionnalités supplémentaires ; elles se contentent simplement d’hériter de Exception. Par conséquent, l’examen des propriétés de la Exception classe vous permet de comprendre la plupart des exceptions et comment vous pouvez utiliser une exception dans votre code.

Voici les propriétés de la Exception classe :

  • Données : la Data propriété contient des données arbitraires dans des paires clé-valeur.
  • HelpLink : la HelpLink propriété peut être utilisée pour contenir une URL (ou URN) vers un fichier d’aide qui fournit des informations détaillées sur la cause d’une exception.
  • HResult : La HResult propriété peut être utilisée pour accéder à une valeur numérique codée affectée à une exception spécifique.
  • InnerException : la InnerException propriété peut être utilisée pour créer et conserver une série d’exceptions pendant la gestion des exceptions.
  • Message : la Message propriété fournit des détails sur la cause d’une exception.
  • Source : La Source propriété peut être utilisée pour accéder au nom de l’application ou à l’objet qui provoque l’erreur.
  • StackTrace : la StackTrace propriété contient une trace de pile qui peut être utilisée pour déterminer où une erreur s’est produite.
  • TargetSite : la TargetSite propriété peut être utilisée pour obtenir la méthode qui lève l’exception actuelle.

C’est correct si vous vous sentez un peu submergé par cet examen des propriétés d’exception, des classes de base et de l’héritage. Ne vous inquiétez pas, l’interception des exceptions dans votre code et l’accès aux propriétés d’une exception sont plus faciles que d’expliquer le fonctionnement des exceptions et des propriétés d’exception.

Remarque

Dans ce module, vous allez vous concentrer sur l’utilisation de la propriété de message d’une exception pour signaler l’exception dans l’interface utilisateur de votre application.

Accéder aux propriétés d’un objet d’exception

Maintenant que vous comprenez les objets d’exception et leurs propriétés, il est temps de commencer à coder.

  1. Mettez à jour votre fichier Program.cs comme suit :

    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. Prenez le temps de passer le code en revue.

    Il s’agit du même code que celui que vous avez vu dans l’unité précédente (le code de solution pour l’activité de défi). Vous savez qu’une exception est levée pendant la méthode WriteMessage. Vous savez également que l’exception est interceptée dans la méthode Process1. Vous utiliserez ce code pour examiner les objets d’exception et les types d’exceptions spécifiques.

  3. Mettez à jour la méthode Process1 comme ceci :

    static void Process1()
    {
        try
        {
            WriteMessage();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Exception caught in Process1: {ex.Message}");
        }
    }
    
  4. Prenez une minute pour examiner vos mises à jour.

    Notez que votre clause mise à jour catch intercepte une instance de la Exception classe dans un objet nommé ex. Notez également que votre Console.WriteLine() méthode utilise ex pour accéder à la propriété de l’objet Message et afficher le message d’erreur dans la console.

    Bien que la catch clause puisse être utilisée sans arguments, cette approche n’est pas recommandée. Si vous ne spécifiez pas d’argument, tous les types d’exceptions sont interceptés et vous ne pouvez pas les discerner.

    En règle générale, vous ne devez intercepter que les exceptions à partir de lesquelles votre code sait comment récupérer. Par conséquent, votre catch clause doit spécifier un argument d’objet dérivé de System.Exception. Le type d’exception doit être aussi spécifique que possible. Cela permet d’éviter d’intercepter les exceptions que votre gestionnaire d’exceptions n’est pas en mesure de résoudre. Vous allez mettre à jour votre code pour intercepter un type d’exception spécifique plus loin dans cet exercice.

  5. Dans le menu Fichier , sélectionnez Enregistrer.

  6. Définissez le point d’arrêt sur la ligne de code suivante :

    Console.WriteLine($"Exception caught in Process1: {ex.Message}");
    
  7. Dans le menu Exécuter , sélectionnez Démarrer le débogage

    L’exécution du code doit s’interrompre au point d’arrêt.

  8. Placez le curseur de la souris sur ex.

    Notez que IntelliSense affiche les mêmes propriétés d’exception que celles que vous avez examinées précédemment.

  9. Prenez une minute pour examiner les informations décrivant l’objet exd’exception.

    Notez que l’exception est un type d’exception System.DivideByZeroException et que la Message propriété est définie sur Attempted to divide by zero..

    Notez que la StackTrace propriété signale la méthode et le numéro de ligne où l’erreur s’est produite, ainsi que la séquence d’appels de méthode (et numéros de ligne) qui ont conduit à l’erreur.

  10. Dans la barre d’outils Déboguer, sélectionnez Continuer.

  11. Prenez une minute pour examiner la sortie de la console.

    Notez que la propriété de Message l’exception est incluse dans la sortie générée par votre application :

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

Intercepter un type d’exception spécifique

Maintenant que vous connaissez le type d’exception à intercepter, vous pouvez mettre à jour votre catch clause pour gérer ce type d’exception spécifique.

  1. Mettez à jour la méthode Process1 comme ceci :

    static void Process1()
    {
        try
        {
            WriteMessage();
        }
        catch (DivideByZeroException ex)
        {
            Console.WriteLine($"Exception caught in Process1: {ex.Message}");
        }
    }
    
  2. Enregistrez votre code, puis démarrez une session de débogage.

  3. Notez que votre application mise à jour signale les mêmes messages à la console.

    Bien que les messages signalés soient identiques, il existe une différence importante. Votre Process1 méthode intercepte uniquement les exceptions du type spécifique qu’elle est prête à gérer.

  4. Pour générer un autre type d’exception, mettez à jour la WriteMessage méthode comme suit :

    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. Notez l’utilisation de l’instruction checked .

    Lorsque vous effectuez des calculs de type intégral qui attribuent la valeur d’un type intégral à un autre type intégral, le résultat dépend du contexte de vérification de dépassement de capacité. Dans un checked contexte, la conversion réussit si la valeur source se trouve dans la plage du type de destination. Sinon, une exception OverflowException est levée. Dans un contexte non vérifié, la conversion réussit toujours et se poursuit comme suit :

    • Si le type source est supérieur au type de destination, la valeur source est tronquée en ignorant ses bits « supplémentaires » les plus significatifs. Le résultat est ensuite traité comme une valeur du type de destination.

    • Si le type source est plus petit que le type de destination, la valeur source est étendue par signe ou étendue zéro afin qu’elle soit de la même taille que le type de destination. L’extension de signe est utilisée si le type source est signé ; l’extension à zéro est utilisée si le type source est non signé. Le résultat est ensuite traité comme une valeur du type de destination.

    • Si le type source est de la même taille que le type de destination, la valeur source est traitée comme une valeur du type de destination.

    Remarque

    Les calculs de type intégral qui ne sont pas à l’intérieur d’un checked bloc de code sont traités comme s’ils se trouvent à l’intérieur d’un unchecked bloc de code.

  6. Enregistrez votre code, puis démarrez une session de débogage.

  7. Notez qu’un nouveau type d’exception est intercepté par la catch clause dans les instructions de niveau supérieur plutôt qu’à l’intérieur de la Process1 méthode.

    Votre application imprime les messages suivants dans la console :

    ∞
    An exception has occurred
    Exit program
    

    Remarque

    Le catch bloc dans Process1 n’est pas exécuté. Il s’agit du comportement souhaité. Interceptez uniquement les exceptions que votre code est prêt à gérer.

Intercepter plusieurs exceptions dans un bloc de code

À ce stade, vous vous demandez peut-être ce qui se passe quand plusieurs exceptions se produisent dans un bloc de code unique. Votre code catch gérera-t-il chaque exception au fur et à mesure qu’elles se produisent ?

  1. Mettez à jour la méthode WriteMessage comme ceci :

    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. Définissez le point d’arrêt à l’intérieur de la WriteMessage() méthode sur la ligne de code suivante :

    Console.WriteLine(float1 / float2);
    
  3. Enregistrez votre code, puis démarrez une session de débogage.

  4. Parcourez votre code une ligne à la fois et notez ce qui se passe après que votre code gère la première exception.

    Lorsque la première exception se produit, le contrôle est passé à la première catch clause qui peut gérer l’exception. Le code qui générerait la deuxième exception n’est jamais atteint. Cela signifie que certains de votre code ne sont jamais exécutés. Cela pourrait entraîner des problèmes sérieux.

  5. Prenez une minute pour prendre en compte la façon dont vous pouvez gérer plusieurs exceptions et quand/pourquoi vous ne souhaiterez peut-être pas que votre code gère plusieurs exceptions.

    Vous avez appris précédemment dans ce module que les exceptions doivent être interceptées aussi près de l’endroit où elles se produisent que possible. Dans cet esprit, vous pouvez choisir de mettre à jour la méthode WriteMessage pour intercepter des exceptions à l’aide de son propre try-catch. Par exemple:

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

    Vous pouvez également encapsuler le code qui provoque le OverflowException dans un try-catch distinct à l'intérieur de la méthode WriteMessage().

    checked
    {
        try
        {
            smallNumber = (byte)number1;
        }
        catch (OverflowException ex)
        {
            Console.WriteLine($"Exception caught in WriteMessage: {ex.Message}");
        }  
    }
    
  6. Dans quelles conditions ne serait-il pas souhaitable d’intercepter les exceptions suivantes ?

    Considérez le cas lorsque votre méthode (ou bloc de code) termine un processus en deux parties. Supposons que la deuxième partie du processus dépend de la première partie terminée. Si la première partie du processus ne peut pas se terminer correctement, il n’y a aucun point à passer à la deuxième partie du processus. Dans ce cas, il est souvent préférable de présenter à l’utilisateur un message expliquant la condition d’erreur sans tenter la partie ou les parties restantes du processus plus volumineux.

Intercepter des types d’exceptions distincts dans un bloc de code

Il existe des moments où des variations de vos données peuvent entraîner différents types d’exceptions.

  1. Effacez vos points d’arrêt, puis remplacez le contenu de votre fichier Program.cs par le code suivant :

    // 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. Prenez une minute pour passer en revue ce code.

    Tout d’abord, le code crée un tableau de chaînes nommé inputValues. Les données du tableau sont destinées à représenter les valeurs d’entrée entrées par un utilisateur qui a été invité à entrer des valeurs numériques. Selon la valeur entrée, différents types d’exceptions peuvent se produire.

    Notez que le code utilise la int.Parse méthode pour convertir les valeurs de chaîne « input » en entiers. Le int.Parse code est placé à l’intérieur d’un try bloc de code.

  3. Définissez un point d’arrêt sur la ligne de code suivante :

    int numValue = 0;
    
  4. Enregistrez votre code, puis démarrez une session de débogage.

  5. Parcourez le code une ligne à la fois et notez que différents types d’exceptions sont interceptés.

Récapitulatif

Voici quelques points importants à retenir de cette unité :

  • La catch clause doit être configurée pour intercepter un type d’exception spécifique. Par exemple, le type d’exception DivideByZeroException .
  • Les propriétés d’un objet d’exception sont accessibles dans le catch bloc. Par exemple, vous pouvez utiliser la Message propriété pour informer l’utilisateur de l’application d’un problème.
  • Vous pouvez spécifier deux clauses ou plus catch lorsque vous devez intercepter plusieurs types d’exception.