Que se passe-t-il si un bloc finalement jette une exception?

Si un bloc finalement jette une exception, que se passe-t-il exactement ?

Plus précisément, que se passe-t-il si l’exception est lancée au milieu d’un bloc Le rest des instructions (après) dans ce bloc est-il invoqué?

Je suis conscient que les exceptions se propageront à la hausse.

Si un bloc lance une exception, que se passe-t-il exactement ?

Cette exception se propage et s’exécute et sera (peut) être traitée à un niveau supérieur.

Votre bloc final ne sera pas terminé au-delà du point où l’exception est lancée.

Si le bloc finally était en cours d’exécution lors du traitement d’une exception antérieure, cette première exception est perdue.

C # 4 Spécification de langage § 8.9.5: Si le bloc last lève une autre exception, le traitement de l’exception en cours est terminé.

Pour des questions comme celles-ci, j’ouvre généralement un projet d’application de console vide dans Visual Studio et écris un petit programme:

 using System; class Program { static void Main(ssortingng[] args) { try { try { throw new Exception("exception thrown from try block"); } catch (Exception ex) { Console.WriteLine("Inner catch block handling {0}.", ex.Message); throw; } finally { Console.WriteLine("Inner finally block"); throw new Exception("exception thrown from finally block"); Console.WriteLine("This line is never reached"); } } catch (Exception ex) { Console.WriteLine("Outer catch block handling {0}.", ex.Message); } finally { Console.WriteLine("Outer finally block"); } } } 

Lorsque vous exécutez le programme, vous verrez l’ordre exact dans lequel catch blocs catch et finally sont exécutés. Veuillez noter que le code dans le bloc finally après que l’exception soit lancée ne sera pas exécuté (en fait, dans ce programme exemple, Visual Studio vous avertira même qu’il a détecté du code inaccessible):

 Exception de gestion des blocages internes lancée à partir du bloc try.
 Bloc intérieur
 Exception de gestion du bloc catch externe lancée depuis bloc bloc.
 Bloc externe

Remarque supplémentaire

Comme Michael Damatov l’a souligné, une exception du bloc try sera “consommée” si vous ne la gérez pas dans un bloc catch (interne). En fait, dans l’exemple ci-dessus, l’exception renvoyée n’apparaît pas dans le bloc catch externe. Pour rendre cela encore plus clair, regardez l’échantillon suivant légèrement modifié:

 using System; class Program { static void Main(ssortingng[] args) { try { try { throw new Exception("exception thrown from try block"); } finally { Console.WriteLine("Inner finally block"); throw new Exception("exception thrown from finally block"); Console.WriteLine("This line is never reached"); } } catch (Exception ex) { Console.WriteLine("Outer catch block handling {0}.", ex.Message); } finally { Console.WriteLine("Outer finally block"); } } } 

Comme vous pouvez le voir sur la sortie, l’exception interne est “perdue” (c’est-à-dire ignorée):

 Bloc intérieur
 Exception de gestion du bloc catch externe lancée depuis bloc bloc.
 Bloc externe

S’il y a une exception en attente (lorsque le bloc try a un catch mais pas de catch ), la nouvelle exception remplace celle-ci.

S’il n’y a pas d’exception en attente, cela fonctionne comme si une exception était générée en dehors du bloc finally .

L’exception est propagée.

Extrait rapide (et plutôt évident) pour enregistrer “exception d’origine” (jetée dans le bloc try ) et sacrifier “finalement l’exception” (jeté dans bloc finally ), au cas où l’original est plus important pour vous:

 try { throw new Exception("Original Exception"); } finally { try { throw new Exception("Finally Exception"); } catch { } } 

Lorsque le code ci-dessus est exécuté, “Exception d’origine” propage la stack d’appels et “Finalement, une exception” est perdue.

Je devais le faire pour détecter une erreur en essayant de fermer un stream qui n’avait jamais été ouvert à cause d’une exception.

 errorMessage = ssortingng.Empty; try { byte[] requestBytes = System.Text.Encoding.ASCII.GetBytes(xmlFileContent); webRequest = WebRequest.Create(url); webRequest.Method = "POST"; webRequest.ContentType = "text/xml;charset=utf-8"; webRequest.ContentLength = requestBytes.Length; //send the request using (var sw = webRequest.GetRequestStream()) { sw.Write(requestBytes, 0, requestBytes.Length); } //get the response webResponse = webRequest.GetResponse(); using (var sr = new StreamReader(webResponse.GetResponseStream())) { returnVal = sr.ReadToEnd(); sr.Close(); } } catch (Exception ex) { errorMessage = ex.ToSsortingng(); } finally { try { if (webRequest.GetRequestStream() != null) webRequest.GetRequestStream().Close(); if (webResponse.GetResponseStream() != null) webResponse.GetResponseStream().Close(); } catch (Exception exw) { errorMessage = exw.ToSsortingng(); } } 

si le webRequest a été créé mais une erreur de connexion est survenue pendant la

 using (var sw = webRequest.GetRequestStream()) 

alors, finalement, attraper une exception en essayant de fermer les connexions qu’il pensait être ouvert parce que webRequest avait été créé.

Si le fichier ne comportait pas de try-catch, ce code provoquerait une exception non gérée lors du nettoyage de la requête webRequest.

 if (webRequest.GetRequestStream() != null) 

à partir de là, le code sortirait sans traiter correctement l’erreur qui s’est produite et donc causer des problèmes pour la méthode d’appel.

J’espère que cela aide comme exemple

Lancer une exception alors qu’une autre exception est active entraînera le remplacement de la première exception par la deuxième exception (ultérieure).

Voici un code qui illustre ce qui se passe:

  public static void Main(ssortingng[] args) { try { try { throw new Exception("first exception"); } finally { //try { throw new Exception("second exception"); } //catch (Exception) { //throw; } } } catch (Exception e) { Console.WriteLine(e); } } 
  • Exécutez le code et vous verrez “seconde exception”
  • Décommentez les instructions try et catch et vous verrez “première exception”
  • Décommentez aussi le jet; déclaration et vous verrez “deuxième exception” à nouveau.

Il y a quelques mois, j’ai aussi fait face à quelque chose comme ça,

  private void RaiseException(Ssortingng errorMessage) { throw new Exception(errorMessage); } private void DoTaskForFinally() { RaiseException("Error for finally"); } private void DoTaskForCatch() { RaiseException("Error for catch"); } private void DoTaskForTry() { RaiseException("Error for try"); } try { /*lacks the exception*/ DoTaskForTry(); } catch (Exception exception) { /*lacks the exception*/ DoTaskForCatch(); } finally { /*the result exception*/ DoTaskForFinally(); } 

Pour résoudre ce problème, j’ai fait une classe d’utilitaire comme

 class ProcessHandler : Exception { private enum ProcessType { Try, Catch, Finally, } private Boolean _hasException; private Boolean _hasTryException; private Boolean _hasCatchException; private Boolean _hasFinnallyException; public Boolean HasException { get { return _hasException; } } public Boolean HasTryException { get { return _hasTryException; } } public Boolean HasCatchException { get { return _hasCatchException; } } public Boolean HasFinnallyException { get { return _hasFinnallyException; } } public Dictionary Exceptions { get; private set; } public readonly Action TryAction; public readonly Action CatchAction; public readonly Action FinallyAction; public ProcessHandler(Action tryAction = null, Action catchAction = null, Action finallyAction = null) { TryAction = tryAction; CatchAction = catchAction; FinallyAction = finallyAction; _hasException = false; _hasTryException = false; _hasCatchException = false; _hasFinnallyException = false; Exceptions = new Dictionary(); } private void Invoke(Action action, ref Boolean isError, ProcessType processType) { try { action.Invoke(); } catch (Exception exception) { _hasException = true; isError = true; Exceptions.Add(processType.ToSsortingng(), exception); } } private void InvokeTryAction() { if (TryAction == null) { return; } Invoke(TryAction, ref _hasTryException, ProcessType.Try); } private void InvokeCatchAction() { if (CatchAction == null) { return; } Invoke(TryAction, ref _hasCatchException, ProcessType.Catch); } private void InvokeFinallyAction() { if (FinallyAction == null) { return; } Invoke(TryAction, ref _hasFinnallyException, ProcessType.Finally); } public void InvokeActions() { InvokeTryAction(); if (HasTryException) { InvokeCatchAction(); } InvokeFinallyAction(); if (HasException) { throw this; } } } 

Et utilisé comme ça

 try { ProcessHandler handler = new ProcessHandler(DoTaskForTry, DoTaskForCatch, DoTaskForFinally); handler.InvokeActions(); } catch (Exception exception) { var processError = exception as ProcessHandler; /*this exception contains all exceptions*/ throw new Exception("Error to Process Actions", exception); } 

mais si vous voulez utiliser des parameters et des types de retour, c’est une autre histoire

 public void MyMethod() { try { } catch{} finally { CodeA } CodeB } 

La façon dont les exceptions lancées par CodeA et CodeB sont traitées est la même.

Une exception lancée dans un bloc finally n’a rien de spécial, traitez-la comme une exception lancée par le code B.

L’exception se propage et doit être traitée à un niveau supérieur. Si l’exception n’est pas gérée au niveau supérieur, l’application se bloque. L’exécution du bloc “finally” s’arrête au point où l’exception est levée.

Indépendamment du fait qu’il y ait une exception ou non, le bloc “finally” est garanti pour s’exécuter.

  1. Si le bloc “finally” est exécuté après qu’une exception soit survenue dans le bloc try,

  2. et si cette exception n’est pas gérée

  3. et si le bloc finalement jette une exception

Ensuite, l’exception d’origine qui s’est produite dans le bloc try est perdue.

 public class Exception { public static void Main() { try { SomeMethod(); } catch (Exception ex) { Console.WriteLine(ex.Message); } } public static void SomeMethod() { try { // This exception will be lost throw new Exception("Exception in try block"); } finally { throw new Exception("Exception in finally block"); } } } 

Excellent article pour les détails

Il jette une exception;) Vous pouvez intercepter cette exception dans une autre clause catch.