Partager via


Gestion des exceptions (Guide de programmation C#)

Un bloc try est utilisé par les programmeurs C# pour partitionner du code susceptible d’être affecté par une exception. Les blocs catch associés sont utilisés pour gérer les exceptions résultantes. Un bloc finally contient du code qui est exécuté qu'une exception soit levée ou non dans le bloc try, par exemple la libération de ressources allouées dans le bloc try. Un try bloc nécessite un ou plusieurs blocs associés catch , ou un finally bloc, ou les deux.

Les exemples suivants montrent une try-catch instruction, une try-finally instruction et une try-catch-finally instruction.

try
{
    // Code to try goes here.
}
catch (SomeSpecificException ex)
{
    // Code to handle the exception goes here.
    // Only catch exceptions that you know how to handle.
    // Never catch base class System.Exception without
    // rethrowing it at the end of the catch block.
}
try
{
    // Code to try goes here.
}
finally
{
    // Code to execute after the try block goes here.
}
try
{
    // Code to try goes here.
}
catch (SomeSpecificException ex)
{
    // Code to handle the exception goes here.
}
finally
{
    // Code to execute after the try (and possibly catch) blocks
    // goes here.
}

Un bloc try sans bloc catch ou bloc finally entraîne une erreur du compilateur.

Blocs catch

Un catch bloc peut spécifier le type d’exception à intercepter. La spécification de type est appelée filtre d’exception. Le type d’exception doit être dérivé de Exception. En règle générale, ne spécifiez Exception pas comme filtre d’exception, sauf si vous savez comment gérer toutes les exceptions qui peuvent être levées dans le try bloc, ou si vous avez inclus une throw instruction à la fin de votre catch bloc.

Plusieurs catch blocs avec différentes classes d’exception peuvent être chaînés ensemble. Les catch blocs sont évalués de haut en bas dans votre code, mais un catch seul bloc est exécuté pour chaque exception levée. Le premier catch bloc qui spécifie le type exact ou une classe de base de l’exception levée est exécuté. Si aucun bloc catch ne spécifie une classe d’exception correspondante, un bloc catch sans type est sélectionné, s’il y en a un dans l’instruction. Il est important de positionner catch les blocs avec les classes d’exception les plus spécifiques (c’est-à-dire les plus dérivées) en premier.

Interceptez les exceptions quand les conditions suivantes sont remplies :

  • Vous avez une bonne compréhension de la raison pour laquelle l’exception peut être levée et vous pouvez implémenter une récupération spécifique, par exemple inviter l’utilisateur à entrer un nouveau nom de fichier lorsque vous interceptez un FileNotFoundException objet.
  • Vous pouvez créer et lever une exception plus spécifique.
    int GetInt(int[] array, int index)
    {
        try
        {
            return array[index];
        }
        catch (IndexOutOfRangeException e)
        {
            throw new ArgumentOutOfRangeException(
                "Parameter index is out of range.", e);
        }
    }
    
  • Vous souhaitez gérer partiellement une exception avant de la transmettre pour plus de gestion. Dans l’exemple suivant, un catch bloc est utilisé pour ajouter une entrée à un journal des erreurs avant de relancer l’exception.
    try
    {
        // Try to access a resource.
    }
    catch (UnauthorizedAccessException e)
    {
        // Call a custom error logging procedure.
        LogError(e);
        // Re-throw the error.
        throw;
    }
    

Vous pouvez également spécifier des filtres d’exception pour ajouter une expression booléenne à une clause catch. Les filtres d’exceptions indiquent qu’une clause catch spécifique correspond uniquement lorsque cette condition est vraie. Dans l’exemple suivant, les deux clauses catch utilisent la même classe d’exception, mais une condition supplémentaire est vérifiée pour créer un message d’erreur différent :

int GetInt(int[] array, int index)
{
    try
    {
        return array[index];
    }
    catch (IndexOutOfRangeException e) when (index < 0) 
    {
        throw new ArgumentOutOfRangeException(
            "Parameter index cannot be negative.", e);
    }
    catch (IndexOutOfRangeException e)
    {
        throw new ArgumentOutOfRangeException(
            "Parameter index cannot be greater than the array size.", e);
    }
}

Un filtre d’exceptions qui retourne false toujours peut être utilisé pour examiner toutes les exceptions, mais pas les traiter. Une utilisation classique consiste à journaliser les exceptions :

public class ExceptionFilter
{
    public static void Main()
    {
        try
        {
            string? s = null;
            Console.WriteLine(s.Length);
        }
        catch (Exception e) when (LogException(e))
        {
        }
        Console.WriteLine("Exception must have been handled");
    }

    private static bool LogException(Exception e)
    {
        Console.WriteLine($"\tIn the log routine. Caught {e.GetType()}");
        Console.WriteLine($"\tMessage: {e.Message}");
        return false;
    }
}

La méthode LogException retourne toujours false, aucune clause catch utilisant ce filtre d’exception ne correspond. La clause catch peut être générale et utiliser System.Exception. Les clauses ultérieures peuvent traiter des classes d’exception plus spécifiques.

Blocs Finally

Un finally bloc vous permet de nettoyer les actions effectuées dans un try bloc. S’il est présent, le finally bloc s’exécute en dernier, après le try bloc et tout bloc correspondant catch . Un finally bloc s’exécute toujours, qu’une exception soit levée ou qu’un catch bloc correspondant au type d’exception soit trouvé.

Le finally bloc peut être utilisé pour libérer des ressources telles que des flux de fichiers, des connexions de base de données et des handles graphiques sans attendre que le garbage collector dans l’exécution finalise les objets.

Dans l’exemple suivant, le finally bloc est utilisé pour fermer un fichier ouvert dans le try bloc. Notez que l’état du handle de fichier est vérifié avant la fermeture du fichier. Si le try bloc ne peut pas ouvrir le fichier, le handle de fichier a toujours la valeur null et le finally bloc n’essaie pas de le fermer. Au lieu de cela, si le fichier est ouvert correctement dans le try bloc, le finally bloc ferme le fichier ouvert.

FileStream? file = null;
FileInfo fileinfo = new System.IO.FileInfo("./file.txt");
try
{
    file = fileinfo.OpenWrite();
    file.WriteByte(0xF);
}
finally
{
    // Check for null because OpenWrite might have failed.
    file?.Close();
}

Spécification du langage C#

Pour plus d’informations, consultez Exceptions et l’instruction Try dans la spécification du langage C#. La spécification du langage est la source de référence pour la syntaxe C# et son utilisation.

Voir aussi