J'examine un code pour un ami et dis qu'il utilisait une déclaration de retour à l'intérieur d'un bloc try-finally. Le code de la section Enfin se déclenche-t-il même si le reste du bloc try ne fonctionne pas?
Exemple:
public bool someMethod()
{
try
{
return true;
throw new Exception("test"); // doesn't seem to get executed
}
finally
{
//code in question
}
}
c#
.net
exception-handling
try-catch
JamesEggers
la source
la source
StackOverflowException
enExecutionEngineException
sont certaines. Et comme ils ne peuvent pas être traités,finally
ils ne fonctionneront pas.try
bloc. Rien sur un programme brutal n'est abandonné.try
bloc est unereturn
instruction. (La deuxième déclaration de ce bloc est inaccessible et générera un avertissement.)Réponses:
Réponse simple: oui.
la source
finally
bloc s'exécute.Normalement, oui. La section finally est garantie d'exécuter tout ce qui se passe, y compris les exceptions ou l'instruction 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 les régions d'exécution contraintes .
la source
Voici un petit test:
Le résultat est:
la source
WriteLine
le résultat de l'appel de méthode est réellement exécuté. Dans ce cas, l'return
appel définit le résultat des méthodes, écrit finalement sur la console - avant la fin de la méthode. Ensuite,WriteLine
dans la méthode Main crache le texte de l'appel de retour.Citation de MSDN
la source
finally
à fait fausse: en fait, elle ne garantit rien, même pour des programmes parfaitement ordinaires (ce qui est arrivé à jeter cette exception).En règle générale, oui, le enfin s'exécute.
Pour les trois scénarios suivants, le enfin fonctionnera TOUJOURS :
Cela inclut les exceptions conformes CLS qui dérivent de System.Exception et les exceptions 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 lever d'exceptions de réclamation non CLS, mais les langages tels que C ++ le peuvent. C # pourrait appeler du code écrit dans un langage qui peut lever des exceptions non conformes CLS.
partir de .NET 2.0, une ThreadAbortException n'empêchera plus finalement un de s'exécuter. ThreadAbortException est maintenant hissé avant ou après le finalement. 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 du thread ne se produise.
Le scénario suivant, enfin, ne s'exécutera pas:
StackOverflowException asynchrone.
À partir de .NET 2.0, un débordement de pile entraînera la fin du processus. Le finally ne sera pas exécuté, à moins qu'une autre contrainte ne soit appliquée pour faire enfin du CER une 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 s'il est essentiel que le code de nettoyage s'exécute toujours - une fois que tout le processus s'est arrêté en cas de débordement de pile et que tous les objets gérés seront donc nettoyés par défaut. Ainsi, le seul endroit où une CER devrait être pertinente est pour 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 managé est encapsulé par une classe gérée avant d'être consommé par le code utilisateur. La classe wrapper managé utilise généralement un SafeHandle pour encapsuler le handle non managé. SafeHandle implémente un finaliseur critique et une méthode Release exécutée dans une CER pour garantir l'exécution du code de nettoyage. Pour cette raison, vous ne devriez pas voir les URCE jonchées de code utilisateur complet.
Ainsi, 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 de toute façon. Si vous avez un cas limite où vous devez nettoyer une ressource non managée, en dehors d'un SafeHandle ou CriticalFinalizerObject, utilisez un CER comme suit; mais veuillez noter qu'il s'agit d'une mauvaise pratique - le concept non managé doit être abstrait pour une ou plusieurs classes gérées et des SafeHandle appropriés par conception.
par exemple,
la source
FailFast
interne. La seule façon dont j'ai réussi à les attraper est de personnaliser l'hébergement d'exécution CLR . Notez que votre point est toujours valide pour certaines autres exceptions asynchrones.Il y a une exception très importante à cela que je n'ai pas vue mentionnée dans d'autres réponses, et que (après avoir programmé en C # pendant 18 ans) je ne peux pas croire que je ne savais pas.
Si vous lancez ou déclenchez une exception de quelque sorte à l'intérieur de votre
catch
bloc (pas seulement bizarreStackOverflowExceptions
et des choses de ce genre), et que vous n'avez pas letry/catch/finally
bloc entier dans un autretry/catch
bloc, votrefinally
bloc ne s'exécutera pas. Cela est facilement démontré - et si je ne l'avais pas vu moi-même, étant donné la fréquence à laquelle j'ai lu que ce ne sont que des cas d'angle vraiment étranges et minuscules qui peuvent empêcher unfinally
bloc de s'exécuter, je ne l'aurais pas cru.Je suis sûr qu'il y a une raison à cela, mais c'est bizarre que ce ne soit pas plus largement connu. (C'est noté ici par exemple, mais pas n'importe où dans cette question particulière.)
la source
finally
bloc n'est tout simplement pas un piège pour lecatch
bloc.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ù en effet une exception est 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 une opération de déroulement d' exception."
L' exécution du bloc finally n'est garantie que si une autre fonction (telle que Main) plus haut dans la pile des appels intercepte l'exception. Ce détail n'est généralement pas un problème car tous les environnements d'exécution (CLR et OS) C # s'exécutent sur la plupart des ressources libres qu'un processus possède à sa fermeture (descripteurs de fichiers, etc.). Dans certains cas, cela peut être crucial cependant: Une opération de base de données à moitié en cours que vous souhaitez valider resp. se détendre; ou une connexion à distance qui peut ne pas être fermée automatiquement par le système d'exploitation, puis bloque un serveur.
la source
Oui. C'est en fait ce point principal d'une déclaration finale. À moins que quelque chose ne se produise (par manque de mémoire, ordinateur débranché, etc.), l'instruction finally doit toujours être exécutée.
la source
finally
bloc si cette exception n'est jamais interceptée. Cela m'a pris par surprise ;-).Il ne se déclenchera pas non plus lors d'une exception non capturée et s'exécutera 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
la source
ne fonctionnera finalement pas si vous quittez l'application en utilisant System.exit (0); un péché
le résultat serait juste: essayez
la source
c#
, mais cela semble être le casJava
. Et en plus de cela, dans la plupart des cas,System.exit()
c'est un soupçon de mauvaise conception :-)Dans 99% des scénarios, il sera garanti que le code à l'intérieur du
finally
bloc s'exécutera, cependant, pensez à ce scénario: vous avez un thread qui a untry
->finally
bloc (noncatch
) et vous obtenez une exception non gérée dans ce thread. Dans ce cas, le thread se fermera et sonfinally
bloc 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 des conditions rares, "Non".
la source
Le but principal de finalement block est d'exécuter tout ce qui y est écrit. 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.
la source