Programmation C sharp/Les exceptions

Un livre de Wikilivres.
Programmation C#
Programmation C#
Modifier ce modèle

Une exception est créée et lancée quand une erreur survient. Elle se propage dans la pile d'appel de la manière suivante : à partir du moment où elle est lancée, l'exécution normale est interrompue, et un gestionnaire d'exceptions est recherché dans le bloc d'instruction courant. S'il n'est pas trouvé, la recherche se poursuit dans le bloc englobant celui-ci, ou à défaut, dans le bloc de la fonction appelante, et ainsi de suite... Si la recherche n'aboutit pas, une boîte de dialogue signalant l'exception est affichée.

Attraper une exception[modifier | modifier le wikicode]

Un gestionnaire d'exception attrape une classe d'exception particulière et gère le cas d'erreur correspondant. Ce gestionnaire encadre les instructions à gérer pouvant lancer une exception.

La syntaxe est la suivante :

try
{
    // Une exception peut être lancée
    instructions
}
catch ( classe_d_exception variable )
{
    // Gérer l'erreur en fonction des détails
    // de l'erreur contenus dans la variable
    instructions
}
...autres blocs catch...
finally
{
    // Instructions toujours exécutées
    // exception lancée ou non
    instructions
}

Le bloc try est suivi d'un nombre quelconque de bloc catch (éventuellement aucun) attrapant différents types d'exception, et éventuellement d'un bloc finally qui sera toujours exécuté quoi qu'il se passe.

Exemple :

try
{
    Console.Write("Entrez un nombre : ");
    int n = int.Parse( Console.ReadLine() );
    Console.WriteLine("  100/nombre = "+( 100/n ));
}
catch ( DivideByZeroException dbzex )
{
    Console.Error.WriteLine("  Division par zéro");
}
catch ( Exception ex )
{
    Console.Error.WriteLine(
        "  Une autre exception a eu lieu : "+ex.Message);
}
finally
{
    Console.WriteLine(
        "  Quel que soit le résultat, ceci est affiché");
}

La variable n'est pas obligatoire si le bloc qui attrape l'exception ne l'utilise pas :

Exemple précédent modifié :

try
{
    Console.Write("Entrez un nombre : ");
    int n = int.Parse( Console.ReadLine() );
    Console.WriteLine("  100/nombre = "+( 100/n ));
}
catch ( DivideByZeroException )
{
    Console.Error.WriteLine("  Division par zéro");
}
catch ( Exception ex )
{
    Console.Error.WriteLine(
        "  Une autre exception a eu lieu : "+ex.Message);
}
finally
{
    Console.WriteLine(
        "  Quel que soit le résultat, ceci est affiché");
}

Attraper conditionnellement une exception[modifier | modifier le wikicode]

Depuis C# 6.0 il est possible d'ajouter une clause de condition pour attraper une exception avec le mot-clé when.

La syntaxe est alors la suivante :

catch ( classe_d_exception variable ) when ( expression_de_condition )

L'expression ne peut pas utiliser les variables locales au bloc try, mais peut utiliser l'objet exception.

Exemple pour un traitement selon un code associé à l'exception :

try
{
    InterpreterScript("script.txt");
}
catch ( ScriptException ex ) when (ex.Code == 1001)
{
    Console.Error.WriteLine("Script utilisant un mauvais encodage");
}
catch ( ScriptException ex ) when (ex.Code == 1002)
{
    Console.Error.WriteLine("Variable non trouvée");
}


Libérer des ressources[modifier | modifier le wikicode]

Un bloc finally est utile pour libérer des ressources à la fin d'un traitement, qu'une erreur ait eu lieu ou non.

Exemple :

Bitmap bm;
try
{
    bm=new Bitmap(100,100);
    ...
}
finally
{
    bm.Dispose(); // libérer les ressources
}

Cependant, les classes implémentant l'interface IDisposable ont une méthode Dispose(), et peuvent être utilisées avec le mot clé using :

using( Bitmap bm = new Bitmap(100,100) )  // <- objet IDisposable
{
    ...
} // <- méthode Dispose() appelée automatiquement

Lancer une exception[modifier | modifier le wikicode]

En cas d'erreur dans une méthode d'un programme (arguments invalides, ...), il est possible de lancer une exception en utilisant le mot clé throw.

La syntaxe est la suivante :

throw objet_exception;

objet_exception est une instance de la classe Exception ou de l'une de ses sous-classes.

En général, l'objet exception est alloué en même temps qu'il est lancé :

throw new classe_exception(arguments);

La pile d'appel est enregistrée dans l'objet exception au moment où il est lancé.

Dans un gestionnaire d'exceptions, il est possible de relancer l'exception attrapée en utilisant l'instruction throw sans argument. Ce qui est utile quand le gestionnaire ne gère que partiellement l'erreur qui devra être totalement traitée par un autre gestionnaire d'exceptions. Dans ce cas, la pile d'appel d'origine est conservée.

Exemple :

try
{
    Console.Write("Entrez un nombre : ");
    int n = int.Parse( Console.ReadLine() );
    Console.WriteLine("  100/nombre = "+( 100/nombre ));
}
catch ( DivideByZeroException dbzex )
{
    Console.Error.WriteLine("  Division par zéro");
    throw; // relance la même exception, avec la pile d'appel d'origine
    //throw dbzex; // relance avec une nouvelle pile d'appel
}

Créer une classe d'exception[modifier | modifier le wikicode]

Lancer une exception signale une erreur particulière. Si aucune classe d'exception ne convient ou n'est suffisamment précise, ou si l'exception doit comporter des informations supplémentaires, il est possible de créer une nouvelle classe d'exception.

Pour cela, il faut dériver la classe Exception ou l'une de ses sous-classes. Par convention, toutes ces sous-classes ont un nom se terminant par Exception.

Exemple :

public class ErreurDeScriptException : Exception
{
    // Attributs
    private int ligne,colonne;
    private string fichier;

    // Propriétés (en lecture seule)
    public int Ligne { get { return ligne; } }
    public int Colonne { get { return colonne; } }
    public string Fichier { get { return fichier; } }

    // Constructeur
    public ErreurDeScriptException(
        string message,
        string fichier,
        int ligne,
        int colonne )
        : base(message) // appel au constructeur de la classe Exception
    {
        this.fichier = fichier;
        this.ligne = ligne;
        this.colonne = colonne;
    }
}

Ensuite, cette classe peut être utilisée comme n'importe quelle autre classe d'exception :

if ( arg==null )
    throw new ErreurDeScriptException(
        "Un argument est nécessaire", fichier_script, 10 , 5);