Les exceptions

GESTION DES EXCEPTIONS

 

La gestion des erreurs est un élément indispensable en programmation. Nous abordons ici les erreurs qui surviennent à l'exécution d'un programme. Depuis le langage C++ la gestion des erreurs d'exécution est facilité grâce à un mécanisme élaboré. On appelle exception une erreur générée lors de l'exécution d'un programme ou d'une fonction. Cette exception peut être le résultat d'une erreur ou bien être provoquée par le développeur afin d'alerter le programme appelant d'un situation anormale. Les langages objet disposent de classes d'exception correspondant aux causes de l'exception. En C# la classe la plus haute hiérarchiquement est la classe Exception.

Exemples

Le code suivant :

int n=5;
for(int i=-1;i<3;i++)
n/=i;

plante le programme à l'exécution en générant le message :

fig 1 erreur de division par 0

Le code suivant :

int[] t ={1,2,3,4,5};
int n = t[6];

plante le programme et génère le message:

fig 2 erreur de débordement de tableau

Gestion des exceptions try/catch

Pour intercepter l'erreur, il faut mettre le programme dans un contexte de gestion d'erreur. Ceci se fait grâce à un bloc try.

try
{
int[] t ={1,2,3,4,5};
int n = t[6];
}

Ce contexte doit être suivi d'instructions qui indiquent au programme ce qu'il doit faire en cas d'erreur :

catch (System.IndexOutOfRangeException ex)
{
MessageBox.Show(ex.Message);
}

L'exception est ainsi gérée, cela ne provoque plus l'arrêt du programme mais seulement un message :

fig 3 interception d'une exception

La forme générale d'interception des exception est :

try
{
// code à tester
}
catch (<classe d'exception> nom)
{
code à exécuter pour cette exception
}
catch (<classe d'exception> nom)
{
code à exécuter pour cette exception
}
finally
{
// code qui s'exécute dans tous les cas
}

Commentaires.

  • A un bloc try peut correspondre plusieurs catch, si plusieurs catch sont dans la même hiérarchie de classe, il faut commencer par les exception les plus "pointues"
  • Dans le bloc finally (facultatif) on place le code dont on désire l'exécution dans tous les cas. Par exemple si une connexion est ouverte dans le try, on peut souhaiter la fermer dans le finally et pas à la fin du try.

Déclenchement d'une exception

Le développeur peut décider de lever une exception en utilisant l'instruction throw.

Prenons l'exemple (caricatural...)suivant qui affiche le contenu d'un fichier dans une zone de texte :

fig 4 affichage du contenu d'un fichier

Si le nom du fichier saisi est incorrect, une exception est générée de la classe System.IO.FileNotFoundException :

fig 5 message d'erreur

Le code est le suivant :

private void Affiche(string nomFichier,TextBox tx)
{
      try
      {
             StreamReader fichier = new StreamReader(nomFichier);
             string ligne= fichier.ReadLine();
             tx.Text=ligne;
        }
       catch (System.IO.FileNotFoundException ex)
       {
              MessageBox.Show(ex.Message);
        }
}

Cette fonction est appelée dans l'événement click du bouton "lire fichier"

Affiche(txtNomFic.Text,txtSortie);

Mais nous pouvons vouloir aussi lancer une exception dont le message (par exemple) est différent :

Il suffit de modifier le bloc catch afin de lever une exception :

catch (System.IO.FileNotFoundException ex)
{
throw new System.IO.FileNotFoundException("le fichier n'existe pas");
}

Ce qui donne :

fig 6 exception levée

Validation de saisie.

On peut également utiliser ce mécanisme pour lever une exception qui n'est pas une erreur mais seulement une exception dans un contexte particulier :

Supposons que l'on saisisse des notes et que celles-ci doivent être comprise entre 0 et 20 :

private void ValideNote(int n)
{
       if(n<0 || n>20)
                throw new Exception("Note invalide");
}

L'appel ValideNote(25) va provoquer une exeception que l'on peut intercepter dans un bloc try/catch :

try
{
ValideNote(25);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}

Ceci produit :                                

On peut améliorer cette gestion en utilisant une exception mieux appropriée : ArgumentOutOfRangeException qui permet de récupérer l'argument objet de l'exception :

private void ValideNote(int n)
{
if(n<0 || n>20)
throw new System.ArgumentOutOfRangeException("note",n,"non valide" );
}

Le bloc catch de l'appel doit référencer maintenant ce type d'exception :

try
{
     ValideNote(25);
}
catch (System.ArgumentOutOfRangeException ex)
{
      MessageBox.Show("la note "+ex.ActualValue.ToString()+"n'est pas valide");
}

Ceci provoque :        

Conclusion

  • Utilisez systématiquement les blocs try/catch
  • Catchez des exceptions appropriées à la situation
  • Si plusieurs exceptions sont énumérées, placez le plus spécifiques en premier
  • Il faut prévoir, lorsque l'on écrit une fonction succeptible de lever une exception, de la "propager" à l'aide de l'instruction throw
  • N'utiliser l'instruction throw que pour des exceptions ...exceptionnelles