Comment exécuter le code de nettoyage à l’aide de finally
L’objectif d’une instruction finally
est de vérifier que le nettoyage nécessaire des objets, généralement ceux contenant des ressources externes, se produit immédiatement, même si une exception est levée. Un exemple de nettoyage de ce type est l’appel à Close sur un FileStream immédiatement après son utilisation au lieu d’attendre que l’objet soit récupéré par garbage collection par le Common Language Runtime, comme suit :
static void CodeWithoutCleanup()
{
FileStream? file = null;
FileInfo fileInfo = new FileInfo("./file.txt");
file = fileInfo.OpenWrite();
file.WriteByte(0xF);
file.Close();
}
Exemple
Pour transformer le code précédent en instruction try-catch-finally
, le code de nettoyage est séparé du code actif comme suit.
static void CodeWithCleanup()
{
FileStream? file = null;
FileInfo? fileInfo = null;
try
{
fileInfo = new FileInfo("./file.txt");
file = fileInfo.OpenWrite();
file.WriteByte(0xF);
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine(e.Message);
}
finally
{
file?.Close();
}
}
Comme une exception peut se produire à tout moment dans le bloc try
avant l’appel à OpenWrite()
, ou comme l’appel OpenWrite()
lui-même peut échouer, nous n’avons aucune garantie que le fichier est ouvert quand nous essayons de le fermer. Le bloc finally
ajoute un contrôle pour garantir que l’objet FileStream n’est pas null
avant d’appeler la méthode Close. Sans le contrôle null
, le bloc finally
pourrait lever sa propre NullReferenceException, mais la levée d’exceptions dans des blocs finally
doit être évitée, dans la mesure du possible.
Une connexion de base de données est également susceptible d’être fermée dans un bloc finally
. Le nombre de connexions à un serveur de base de données étant parfois limité, vous devez fermer les connexions de base de données le plus rapidement possible. Si une exception est levée avant que vous puissiez fermer votre connexion, il vaut mieux utiliser le bloc finally
qu’attendre le nettoyage de la mémoire.