Sunteți pe pagina 1din 9

SI6-TP4 1

Expérimenter les exceptions : TP4


I. Mécanisme de base du fonctionnement des exceptions
Pour illustrer le fonctionnement des exceptions en C#, nous allons prendre exemple sur le plus célèbre des gaffeurs :
­ Créer un nouveau projet Visual Studio en mode Console, nommée GesExceptions.
­ Sur l’encadré ci-dessous, surligner
o en jaune l’interception de l’exception,
o en bleu, la levée, la survenue de l’exception,
o encadre en rouge, le bloc dont le fonctionnement ne s’arrêtera si
l’exception survient.
­ Ajouter à ce projet une nouvelle classe nommée GastonLagaffe :
class GastonLagaffe
{
public void trierCourrierEnRetard(int nbLettres)
{
Console.Write("Quoi, " + nbLettres + " lettre(s) à trier ? ");
try
{ Console.WriteLine("OK, OK, je vais m'y mettre...");
if (nbLettres > 2)
throw new Exception("Beaucoup trop de lettres...");
Console.WriteLine("Ouf, j'ai fini.");
}
catch (Exception e)
{ Console.WriteLine("M'enfin ! " + e.Message); }
Console.WriteLine("Après tout ce travail, une sieste s'impose.");
}
}

­ Dans le programme principal (méthode Main() de la classe Program), instancier un objet gaston de la classe
GastonLagaffe puis demande à gaston de trier 2 lettres :
static void Main(string[] args)
{ GastonLagaffe gaston = new GastonLagaffe();
Console.WriteLine("Debout Gaston ! Il faut trier le courrier !");
gaston.trierCourrierEnRetard(2);
Console.ReadKey();
}

­ Vous devriez obtenir le résultat d'exécution ci-dessous :

 Modifiez votre programme principal pour demander à Gaston de trier 3 lettres :


gaston.trierCourrierEnRetard(3);

Le résultat de l'exécution est cette fois différent :

1
SI6-TP4 2

A. Comment expliquer ce changement ?


Analysons l’exécution précédente par débogage (cf. TP3 😉)

 Placer un point d'arrêt sur la première instruction de la méthode trierCourrierEnRetard( ) en cliquant dans la
marge

 Déclencher le débogage (raccourci F5)

 A l’aide de la touche F11, avancer instruction par instruction… suivre le déroulement du tri du courrier avec 2
lettres. Puis pour 3 lettres…

 Avancer jusqu’à… la condition. Cette condition a déclenché une levée d’exception. A noter : Pas d’exécution
de l’affichage de « ouf, j’ai fini. »

 Poursuivre l'exécution ligne à ligne avec F11

 Le bloc catch intercepte l’exception et déclenche le message « d’erreur ».

 Enfin, l’exécution se poursuit avec la dernière instruction de la méthode.

II. Le fonctionnement des exceptions en détail


A. Une exception est une instance de la classe Exception

 Modifier le bloc catch de la méthode trierCourrierEnRetard() pour afficher plus de détails sur l'exception
interceptée.
catch (Exception e)
{ Console.WriteLine("M'enfin ! " + e.Message);
Console.WriteLine("Détails : " + e.ToString());
}

Apparait alors le résultat d'exécution ci-dessous :

La variable e utilisée dans le


bloc catch est en réalité un
objet, instance de la classe
Exception située dans l’espace
de noms System.Exception.
La propriété Message fournit le
message passé en paramètre au
constructeur de l'exception lors
de sa levée...
2
SI6-TP4 3

B. Une exception est un objet


Pour illustrer ce point, aller demander à Gaston de ranger son bureau.
 Ajouter à la classe GastonLagaffe la méthode suivante :
public void rangerBureau()
{ Console.WriteLine("Ranger mon bureau ? Si tu insistes... ");
throw new Exception(" Impossible, l'armoire est déjà pleine !");
}

 Modifier le programme principal afin de tester cette méthode (mettre en commentaire la 1ère méthode),
// gaston.trierCourrierEnRetard(2);
// gaston.trierCourrierEnRetard(3);
gaston.rangerBureau();

 Deux conséquences de l’exécution

on s’y attendait !

Mais aussi

Le message « Exception non gérée » est affiché car, à l’exécution, aucun bloc try { } n’a été détecté en amont qui
indiquerait la possibilité d’avoir des exceptions.

 Ajouter un bloc try et un bloc catch dans la méthode rangerBureau() pour obtenir :

3
SI6-TP4 4

C. Une exception remonte la chaine des appels

Dans l'exemple précédent, une exception levée depuis une méthode a été interceptée dans cette même méthode.
Découvrons ce qui se produit, quand une exception est levée lors d'appels de méthodes en cascade : cas le plus
fréquent !

 Ajouter à la classe GastonLagaffe les méthodes suivantes :


public void faireSignerContrats()
{
try
{
Console.WriteLine("Encore ces contrats ? OK, je les imprime...");
imprimerContrats();
Console.WriteLine("A présent une petite signature...");
ajouterSignature();
Console.WriteLine("Fantasio, les contrats sont signés !");
}
catch (Exception e)
{ Console.WriteLine("M'enfin ! " + e.Message); }
}

private void ajouterSignature()


{ Console.WriteLine("Signez ici, M'sieur Demesmaeker."); }

private void imprimerContrats()


{
Console.WriteLine("D'abord, mettre en route l'imprimante.");
allumerImprimante();
Console.WriteLine("Voilà, c'est fait !");
}

private void allumerImprimante()


{
Console.WriteLine("Voyons comment allumer cette machine...");
throw new Exception("Mais qui a démonté tout l'intérieur ?");
}

 Modifier le programme principal pour obtenir :

L'exception levée dans la méthode allumerImprimante() a été propagée par la méthode imprimerContrats() puis
finalement interceptée dans le bloc catch de la méthode faireSignerContrats() :

4
SI6-TP4 5

Une exception levée remonte la chaîne des appels dans l'ordre inverse, jusqu'à être interceptée dans un bloc
catch. Dans le cas où aucun gestionnaire d'exception n'est trouvé, l'exécution du programme s'arrête avec un
message d'erreur.

5
SI6-TP4 6

D. Les exceptions forment une hiérarchie


Jusqu'à présent, nous avons utilisé uniquement la classe Exception pour véhiculer les exceptions. Il est possible de
créer ses propres classes d'exception à partir des mécanismes de la classe existante Exception.

 Ajouter à votre projet les classes ExceptionMenfin et ExceptionBof, dérivées de la classe mère Exception.
Décrire ces classes permet simplement la modification du message d'erreur de l'exception.

class ExceptionMenfin:Exception
{
public ExceptionMenfin(string Message) : base("M'enfin ! " + Message) { }
}
class ExceptionBof : Exception
{
public ExceptionBof(string Message) : base("Bof ! " + Message) { }
}

 Ajouter à la classe GastonLagaffe, la méthode repondreAuTelephone() ci-dessous :


public void repondreAuTelephone(string appelant)
{ if (appelant == "Mr. Boulier")
{ throw new ExceptionMenfin("Je finis un puzzle."); }
else if (appelant == "Prunelle")
{ throw new ExceptionBof("Pas le temps, je suis dé-bor-dé !"); }
else { Console.WriteLine("Allô, ici Gaston, j'écoute..."); }
}

 Ajouter à la classe principale (Program) la méthode ci-dessous (et pas dans la méthode statique)
private static void appeler(GastonLagaffe gaston, String appelant)
{ Console.WriteLine("Gaston, " + appelant + " au téléphone !");
try
{ gaston.repondreAuTelephone(appelant); }
catch (ExceptionMenfin e)
{ Console.WriteLine("Pas de réponse... Et pourquoi ?");
Console.WriteLine(e.Message);
}
catch (ExceptionBof e)
{
Console.WriteLine("Ca sonne toujours... vous dormez ou quoi ?");
Console.WriteLine(e.Message);
}
}

 Modifier le programme principal pour appeler cette méthode plusieurs fois.



appeler(gaston, "Mr. Boulier");
appeler(gaston, "Prunelle");
appeler(gaston, "Jules-de-chez-Smith");

 Le résultat de l'exécution est le suivant :

L’exception de type ExceptionMenfin a été


interceptée dans le premier bloc catch.

L'exception de type ExceptionBof a été interceptée


dans le second bloc catch.

Lorsqu’une méthode spécifie plusieurs types d'exceptions, il est obligatoire de prendre en compte tous les cas
possibles lors d'un appel de cette méthode.

6
SI6-TP4 7

Remarque : comme les exceptions héritent toutes deux de la classe Exception, il est possible de simplifier l'appel en
interceptant (ou en spécifiant) uniquement Exception de par l’héritage de ces méthodes et ces propriétés.

// version 2 de appeler
private static void appeler(GastonLagaffe gaston, String appelant)
{ Console.WriteLine("Gaston, " + appelant + " au téléphone !");
try
{ gaston.repondreAuTelephone(appelant); }
catch (Exception e)
{ Console.WriteLine("Encore une bonne excuse, j'imagine ?");
Console.WriteLine(e.Message);
}
}
Le résultat de l'exécution est le suivant :

Afin de limiter le nombre de blocs catch, il est intéressant d’intercepter les exceptions décrites par une classe mère
commune à ces exceptions : en particulier, quand le traitement de l'erreur est identique dans tous les catch.

Dans l'exemple précédent, savoir si l'exception interceptée est une ExceptionMenfin ou une ExceptionBof n’a
aucune importance.

III. Rigueur et gestion des exceptions


Les exceptions constituent une amélioration pour gérer les erreurs, à condition de savoir les employer correctement
en se posant des questions importantes :

A. Ne jamais ignorer une exception !


Un autre danger consiste à ignorer l'information importante que constitue l'interception d'une exception. C'est le cas
quand un bloc catch reste vide.

­ Ajouter à la classe GastonLagaffe la méthode commanderFournitures() ci-dessous :

public void commanderFournitures()


{ Console.WriteLine("D'abord, réchauffer ma morue aux fraises...");
Console.WriteLine("Heureusement, j'ai réparé mon réchaud à gaz.");
throw new Exception("Vite, où est l'extincteur ??");
}

­ Ajouter à votre classe principale (Program) la méthode preparerJournal() cidessous :


private static void preparerJournal(GastonLagaffe gaston)
{ Console.WriteLine("Gaston, une commande urgente !");
try
{ gaston.commanderFournitures(); }
Console.WriteLine("Déjà terminé ? Il progresse, ce petit...");
}

Le compilateur signale une erreur : aucun intérêt d’un try sans lever d’exception par un catch.
En effet, sans définition d’un catch dans la méthode preparerJournal(), aucune remontée d’erreur ne peut se
produire dans la méthode appelante commanderFournitures(). L’exception aurait été avalée (en anglais
d'"exception swallowing").

7
SI6-TP4 8

B. Libérer des ressources en présence d'une exception


 Ajouter à la classe GastonLagaffe la méthode preparerCafe() ci-dessous :

public void preparerCafe(string personne)


{
Console.WriteLine("Un café pour " + personne + " ? OK...");
Console.WriteLine("D'abord, j'allume la cafetière.");
Console.WriteLine("Le café chauffe... C'est prêt !");
if (personne != "Moiselle Jeanne")
{ Console.WriteLine("J'ai le temps de faire un peu de chimie.");
throw new Exception("Aïe , je me suis brûlé !");
}
Console.WriteLine("J'éteins la cafetière.");
}
 Modifier le programme principal pour faire appel deux fois à cette méthode :
try
{
gaston.preparerCafe("Moiselle Jeanne");
gaston.preparerCafe("Lebrac");
}
catch (Exception e)
{ Console.WriteLine(e.Message); }

Le résultat attendu est le suivant :


Dans le premier cas (café pour Moiselle Jeanne),
tout s'est bien déroulé et la cafetière allumée a
bien été éteinte.

Par contre, le second appel de la méthode (café


pour Lebrac) a provoqué la levée d'une exception
et... La cafetière est toujours allumée !

Evitons ce genre de situation ; utilisons une clause optionnelle en plus du try ... catch : la clause finally. Le code
placé dans un bloc finally s'exécute dans tous les cas, même si une exception a été levée dans le bloc try.

 Modifier la méthode preparerCafe() de la manière suivante :


public void preparerCafe(string personne)
{
try
{
Console.WriteLine("Un café pour " + personne + " ? OK..,");
Console.WriteLine("D'abord, j'allume la cafetière.");
Console.WriteLine("Le café chauffe... C'est prêt !");
if (personne != "Moiselle Jeanne")
{ Console.WriteLine("J'ai le temps de faire un peu de chimie.");
throw new Exception("Aïe , je me suis brûlé !");
}
}
finally { Console.WriteLine("J'éteins la cafetière.");
}
}

8
SI6-TP4 9

Voici le nouveau résultat

Le code du bloc finally (ici, éteindre la cafetière) a été exécuté que l'exception soit levée ou non.

S-ar putea să vă placă și