Est-ce que le code dans une instruction Finally est déclenché si je retourne une valeur dans un bloc Try

Je passe en revue un code pour un ami et dit qu’il utilisait une déclaration de retour dans un bloc try-finally. Le code dans la section Finally continue-t-il à tirer même si le rest 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 tout ce qui se passe, y compris les exceptions ou les déclarations de retour. 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 l’article sur les régions d’exécution limitées .

Voici un petit test:

 class Class1 { [STAThread] static void Main(ssortingng[] args) { Console.WriteLine("before"); Console.WriteLine(test()); Console.WriteLine("after"); } static ssortingng test() { try { return "return"; } finally { Console.WriteLine("finally"); } } } 

Le résultat est:

 before finally return after 

Citant de MSDN

Finalement, il est utilisé pour garantir qu’un bloc de code d’instruction s’exécute indépendamment de la sortie du bloc try précédent.

En général, oui, le sera enfin exécuté.

Pour les trois scénarios suivants, le sera enfin exécuté:

  1. Aucune exception ne se produit
  2. Exceptions synchrones (exceptions qui se produisent dans un stream de programme normal).
    Cela inclut les exceptions conformes à CLS qui dérivent des exceptions System.Exception et non conformes à CLS, qui ne dérivent pas de System.Exception. Les exceptions non conformes à CLS sont automatiquement encapsulées par RuntimeWrappedException. C # ne peut pas émettre des exceptions de plaintes non-CLS, mais des langages tels que C ++ peuvent. C # pourrait appeler un code écrit dans un langage capable de générer des exceptions non conformes à CLS.
  3. Asynchronous ThreadAbortException
    A partir de .NET 2.0, une exception ThreadAbortException n’empêchera plus une exécution finale. ThreadAbortException est maintenant hissé avant ou après le final. Le finalement s’exécutera toujours et ne sera pas interrompu par un abandon de thread, tant que l’essai a été réellement entré avant que l’abandon de thread ne se soit produit.

Le scénario suivant ne sera pas exécuté:

StackOverflowException asynchrone.
À partir de .NET 2.0, un débordement de stack entraînera la fin du processus. Le finalement ne sera pas exécuté, à moins qu’une contrainte supplémentaire soit appliquée pour rendre le CER enfin (région d’exécution contrainte). Les URCE ne doivent pas être utilisées dans le code utilisateur général. Ils ne doivent être utilisés que lorsque le code de nettoyage doit toujours être exécuté – de toute façon, le processus s’arrête de toute façon au débordement de la stack et tous les objects gérés seront donc nettoyés par défaut. Ainsi, le seul endroit où une CER doit être pertinente concerne les ressources qui sont allouées en dehors du processus, par exemple, les descripteurs non gérés.

En règle générale, le code non géré est encapsulé par une classe gérée avant d’être consommé par le code utilisateur. La classe wrapper géré utilise généralement un SafeHandle pour encapsuler le descripteur non géré. SafeHandle implémente un finaliseur critique et une méthode Release exécutée dans un CER pour garantir l’exécution du code de nettoyage. Pour cette raison, vous ne devriez pas voir de code utilisateur illisible sur les CER.

Donc, le fait que le fichier final ne s’exécute pas sur StackOverflowException ne devrait avoir aucun effet sur le code utilisateur, car le processus se terminera quand même. Si vous avez un cas particulier où vous devez nettoyer certaines ressources non gérées, en dehors d’un SafeHandle ou d’un CriticalFinalizerObject, utilisez un CER comme suit: mais veuillez noter que ceci est une mauvaise pratique – le concept non géré doit être résumé dans une ou plusieurs classes gérées et les 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 à ce que je n’ai pas vu mentionné dans d’autres réponses, et qui (après avoir programmé en C # pendant 18 ans), je n’arrive pas à croire que je ne le savais pas.

Si vous lancez ou déclenchez une exception de quelque sorte que ce soit dans votre bloc catch (pas seulement StackOverflowExceptions bizarres et autres), et que vous ne disposez pas du bloc try/catch/finally dans un autre bloc try/catch , votre bloc finally ne sera pas exécuté. C’est facile à démontrer – et si je ne l’avais pas vu moi-même, vu la fréquence à laquelle j’ai lu que ce ne sont que de minuscules boîtiers qui peuvent empêcher l’exécution d’un bloc, je ne l’aurais pas cru.

 static void Main(ssortingng[] 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 c’est bizarre que ce ne soit pas plus connu. (Il est noté ici par exemple, mais pas n’importe où dans cette question particulière.)

Je me rends compte que je suis en retard à la fête, mais dans le scénario (différent de l’exemple de l’OP), où une exception est levée, les é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 du choix du système d’exploitation de déclencher ou non une opération de décompression.”

Le bloc finally ne peut être exécuté que si une autre fonction (telle que Main) située plus haut dans la stack d’appels intercepte l’exception. Ce détail ne pose généralement pas de problème, car tous les programmes C # exécutés dans des environnements d’exécution (CLR et OS) s’exécutent sur la plupart des ressources dont un processus est propriétaire (descripteurs de fichiers, etc.). Dans certains cas, il peut être crucial: Une opération de firebase database en cours sur laquelle vous voulez vous engager. se détendre; ou une connexion à distance qui peut ne pas être fermée automatiquement par le système d’exploitation et bloque ensuite un serveur.

Oui. C’est en fait ce point essentiel d’une déclaration finale. À moins que quelque chose de catestrophique ne se produise (manque de mémoire, ordinateur débranché, etc.), l’instruction finally doit toujours être exécutée.

enfin, ne s’exécutera 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: essayez

Il ne sera pas non plus déclenché sur une exception non capturée et exécuté dans un thread hébergé dans un service Windows

Enfin, n’est pas exécuté dans un thread s’exécutant dans un service Windows

99% des scénarios garantissent que le code dans le bloc finally sera exécuté, mais pensez à ce scénario: vous avez un thread qui a un try -> finally block (pas de catch ) et vous obtenez une exception non gérée fil. Dans ce cas, le thread va sortir 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”, c’est la plupart du temps “oui” et parfois, dans de rares cas, “non”.

Le but principal de finally 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.How cependant, avec System.Environment.Exit (1), l’application se fermera sans passer à la ligne de code suivante.