J'examine le code d'un ami et dis qu'il utilisait une instruction return dans un bloc try-finally. Le code de la section Finally est-il toujours activé même si le reste du bloc try ne le fait pas?
Exemple:
public bool someMethod()
{
try
{
return true;
throw new Exception("test"); // doesn't seem to get executed
}
finally
{
//code in question
}
}
Réponse simple: oui.
Normalement oui. La section finally est garantie pour exécuter quoi qu'il arrive, y compris les exceptions ou les instructions return. Une exception à cette règle est une exception asynchrone se produisant sur le thread (OutOfMemoryException
, StackOverflowException
).
Pour en savoir plus sur les exceptions asynchrones et le code fiable dans ces situations, consultez la rubrique régions d'exécution contraintes .
Voici un petit test:
class Class1
{
[STAThread]
static void Main(string[] args)
{
Console.WriteLine("before");
Console.WriteLine(test());
Console.WriteLine("after");
}
static string test()
{
try
{
return "return";
}
finally
{
Console.WriteLine("finally");
}
}
}
Le résultat est:
before
finally
return
after
Citant de MSDN
finally est utilisé pour garantir qu'un bloc de code d'instruction est exécuté quelle que soit la manière dont le bloc try précédent est exited .
Généralement oui, le enfin fonctionnera.
Pour les trois scénarios suivants, finalement TOUJOURS sera exécuté:
Le scénario suivant, enfin ne fonctionnera pas:
Asynchrone StackOverflowException.
À partir de .NET 2.0, un débordement de pile entraînera la fin du processus. Enfin, l'exécution ne sera pas exécutée, sauf si une contrainte supplémentaire est appliquée pour lui permettre de devenir enfin une CER (région d'exécution contrainte). Les CER ne doivent pas être utilisés dans le code utilisateur général. Ils ne doivent être utilisés que dans les cas où il est essentiel que le code de nettoyage soit toujours exécuté - une fois que tout le processus est arrêté en cas de débordement de pile, tous les objets gérés sont donc nettoyés par défaut. Ainsi, le seul endroit où un CER devrait être pertinent concerne les ressources allouées en dehors du processus, par exemple les descripteurs non gérés.
Généralement, le code non managé est encapsulé par une classe gérée avant d'être consommé par le code utilisateur. La classe d'encapsuleur gérée utilisera généralement un SafeHandle pour envelopper le descripteur non géré. SafeHandle implémente un finaliseur critique et une méthode Release exécutée dans un CER afin de garantir l'exécution du code de nettoyage. Pour cette raison, vous ne devriez pas voir les CER générés par le code utilisateur.
Donc, le fait que finalement ne s'exécute pas sur StackOverflowException ne devrait pas avoir d'effet sur le code utilisateur, car le processus se terminera quand même. Si vous avez un cas dans lequel vous devez nettoyer une ressource non gérée, en dehors d'un SafeHandle ou d'un CriticalFinalizerObject, utilisez un CER comme suit: mais notez s'il vous plaît que c'est une mauvaise pratique - le concept non géré doit être résumé en une classe (s) gérée (s) et un (x) SafeHandle (s) approprié (s) par conception.
par exemple.,
// No code can appear after this line, before the try
RuntimeHelpers.PrepareConstrainedRegions();
try
{
// This is *NOT* a CER
}
finally
{
// This is a CER; guaranteed to run, if the try was entered,
// even if a StackOverflowException occurs.
}
Il y a une exception très importante à cela que je n'ai pas vue mentionnée dans aucune autre réponse, et pour laquelle (après avoir programmé en C # pendant 18 ans), je ne peux pas croire que je ne le savais pas.
Si vous lancez ou déclenchez une exception de type any à l'intérieur de votre bloc catch
(et pas seulement des noms bizarres StackOverflowExceptions
et autres choses du même genre) et si vous n'avez pas le bloc entier try/catch/finally
dans un autre bloc try/catch
, votre finally
bloc a gagné ' t exécuter. Cela est facile à démontrer - et si je ne l'avais pas vu moi-même, étant donné combien de fois j'ai lu que ce ne sont que des cas minuscules vraiment bizarres qui peuvent empêcher un bloc finally
de s'exécuter, je n'y aurais pas cru.
static void Main(string[] args)
{
Console.WriteLine("Beginning demo of how finally clause doesn't get executed");
try
{
Console.WriteLine("Inside try but before exception.");
throw new Exception("Exception #1");
}
catch (Exception ex)
{
Console.WriteLine($"Inside catch for the exception '{ex.Message}' (before throwing another exception).");
throw;
}
finally
{
Console.WriteLine("This never gets executed, and that seems very, very wrong.");
}
Console.WriteLine("This never gets executed, but I wasn't expecting it to.");
Console.ReadLine();
}
Je suis sûr qu'il y a une raison à cela, mais il est étrange que ce ne soit pas plus connu. (C'est noté ici par exemple, mais pas n'importe où dans cette question particulière.)
Je me rends compte que je suis en retard pour le parti, mais dans le scénario (différent de l'exemple du PO) où une exception est effectivement levée. États MSDN ( https://msdn.Microsoft.com/en-us/library/zwc8s4fz.aspx ): "Si l'exception n'est pas interceptée, l'exécution du bloc finally dépend de la décision du système d'exploitation de déclencher ou non une opération de déroulement de l'exception."
Le bloc finally n'est que garanti à exécuter si une autre fonction (telle que Main) située plus haut dans la pile d'appels intercepte l'exception. Ce détail ne pose généralement pas de problème, car tous les programmes C # d’environnement d’exécution (R & S) s’exécutent sur la plupart des ressources disponibles d’un processus lorsqu’il se termine (descripteurs de fichier, etc.). Dans certains cas, il peut toutefois s'avérer crucial: Une opération de base de données à moitié en cours que vous souhaitez commettre, puis resp. se détendre; ou une connexion distante qui ne peut pas être fermée automatiquement par le système d'exploitation et bloque ensuite un serveur.
Oui. C’est en fait l’essentiel d’une déclaration finale. À moins d'un événement catastrophique (manque de mémoire, ordinateur débranché, etc.), l'instruction finally doit toujours être exécutée.
Il ne sera également pas déclenché sur une exception non capturée et s’exécutant dans un thread hébergé dans un service Windows
Enfin, n'est pas exécuté lorsqu'un thread est exécuté dans un service Windows
enfin, ne fonctionnera pas si vous quittez l'application avec System.exit (0); un péché
try
{
System.out.println("try");
System.exit(0);
}
finally
{
System.out.println("finally");
}
le résultat serait juste: essayer
Oui enfin appeler.
public static bool someMethod()
{
try
{
return true;
throw new Exception("test"); // doesn't seem to get executed
}
finally
{
//code in question
}
}
99% des scénarios garantissent que le code du bloc finally
sera exécuté, mais pensez au scénario suivant: vous avez un thread qui a un bloc try
-> finally
(pas de catch
) et une exception non gérée à l'intérieur de celui-ci. fil. Dans ce cas, le thread se fermera et son bloc finally
ne sera pas exécuté (l'application peut continuer à s'exécuter dans ce cas).
Ce scénario est assez rare, mais c'est seulement pour montrer que la réponse n'est pas TOUJOURS "Oui", mais la plupart du temps "Oui" et parfois, dans de rares cas, "Non".
Enfin, le but final de block est d'exécuter tout ce qui est écrit à l'intérieur. Cela ne devrait pas dépendre de ce qui se passe dans try ou catch.Cependant avec System.Environment.Exit (1), l'application se fermera sans passer à la ligne de code suivante.