85 votes

Le bloc "finally" de C# s'exécute-t-il TOUJOURS ?

Duplicata possible :
Le code contenu dans une instruction Finally sera-t-il ignoré si je renvoie une valeur dans un bloc Try ?

Considérons le code C# suivant. Le bloc "finally" s'exécute-t-il ?

public void DoesThisExecute() {
   string ext = "xlsx";
   string message = string.Empty;
   try {
      switch (ext) {
         case "xls": message = "Great choice!"; break;
         case "csv": message = "Better choice!"; break;
         case "exe": message = "Do not try to break me!"; break;
         default:
            message = "You will not win!";
            return;
      }
   }
   catch (Exception) {
      // Handle an exception.
   }
   finally {
      MessageBox.Show(message);
   }
}

Ha, après avoir fini d'écrire ceci, j'ai réalisé que j'aurais pu faire ce test moi-même dans Visual Studio. Cependant, n'hésitez pas à répondre !

4 votes

Non. Vous obtiendrez une erreur de compilation.

6 votes

La seule chose qui ne compile pas est le point-virgule manquant après la déclaration de 'ext'.

1 votes

@Zano - Le ; manquant était une faute de frappe :)

93voto

Kevin Points 57797

Non, ce n'est pas le cas. Il s'exécutera toujours si l'application est toujours en cours d'exécution (sauf pendant une interruption de service). FastFail exception, Lien MSDN (comme d'autres l'ont fait remarquer). Il s'exécutera lorsqu'il sortira de la partie try/catch du bloc.

Il ne s'exécutera PAS si l'application tombe en panne, si elle est tuée par une commande kill process, etc. C'est très important, car si vous écrivez du code qui attend absolument qu'il s'exécute, par exemple en effectuant manuellement un roll back, et s'il ne s'exécute pas autrement, il s'engage automatiquement, vous pouvez vous retrouver dans un scénario où l'application s'arrête avant que cela ne se produise. Honnêtement, il s'agit d'un scénario extérieur, mais il est important d'en tenir compte dans ces situations.

4 votes

Cela inclut également certaines exceptions (les trois exceptions .net qui ne peuvent pas être attrapées), Application.FailFast ou une panne de courant ( thedailywtf.com/Articles/Mes-Contes.aspx )

0 votes

Et il ne s'exécutera pas si le code ne compile pas et ne s'exécute pas, comme ce sera probablement le cas ici, à cause de l'instruction de retour.

4 votes

@DOK Quel est le problème avec la déclaration de retour ?

64voto

msarchet Points 9059

Extrait de la spécification MSDN C# de la try déclaration :

Les déclarations d'un finally sont toujours exécutés lorsque le contrôle quitte un bloc try déclaration. Cela est vrai, que le transfert de contrôle se produise à la suite d'une exécution normale, à la suite de l'exécution d'une instruction break , continue , goto o return ou à la suite de la propagation d'une exception à partir de l'instruction try déclaration.

Source :

Il y a des cas où le bloc final ne s'exécutera pas :

  1. Environnement.FailFast
  2. Types d'exceptions non rattrapables
  3. Panne d'électricité

0 votes

@Gary Willoughby, je savais que c'était le cas mais je ne voulais pas me tromper alors j'ai cherché les spécifications sur Google.

0 votes

La spécification est fausse. Essayez ceci : static int Main( string[] arguments ) { try { return arguments[1000].Length ; } finally { System.Console.WriteLine( "vous ne verrez jamais ceci !" ) ; } }

0 votes

Wow, on parle de mauvaises réponses à une bonne question.... Il ne s'agit pas d'un doublon de la question indiquée, car celle-ci concernait l'exécution du bloc finally lorsqu'il y avait une instruction de retour dans le bloc try, auquel cas la réponse était la suivante est "Oui". Dans le cas plus général du titre de cette question, il y a au moins trois cas différents où le bloc final sera no être exécutée (même sans tenir compte d'influences extérieures telles qu'une panne du système, un processus tué, etc.) Voir cette question : StackOverflow.com/questions/19549613/

37voto

0xA3 Points 73439

Il n'est pas totalement vrai que finally sera toujours exécuté. Voir cette réponse de Haacked :

Deux possibilités :

  • StackOverflowException
  • ExecutingEngineException

Le bloc final ne sera pas exécuté lorsqu'il y a une StackOverflowException puisqu'il n'y a pas de place sur la pile pour pour exécuter du code supplémentaire. Il ne sera ne sera pas non plus appelé en cas d'exception d'une ExecutingEngineException, ce qui est très rare.

En fait, pour toute sorte d'exception asynchrone (telle que StackOverflowException , OutOfMemoryException , ThreadAbortException ) l'exécution d'un finally n'est pas garanti.

Cependant, ces exceptions sont des exceptions dont vous ne pouvez généralement pas vous remettre, et dans la plupart des cas, votre processus se terminera de toute façon.

En fait, il y a aussi au moins un autre cas où finally n'est pas exécuté comme décrit par Brian Rasmussen dans un maintenant question supprimée :

L'autre cas que je connais est celui où un finaliseur lève une exception. Dans ce cas, le processus cas, le processus est terminé immédiatement aussi, et donc la garantie garantie ne s'applique pas.

Le code ci-dessous illustre le problème

static void Main(string[] args) {
   try {
      DisposableType d = new DisposableType();
      d.Dispose();
      d = null;
      GC.Collect();
      GC.WaitForPendingFinalizers();
   } catch {
      Console.WriteLine("catch");
   } finally {
      Console.WriteLine("finally");
   }
}

public class DisposableType : IDisposable {
   public void Dispose() {
   }

   ~DisposableType() {
      throw new NotImplementedException();
   }
}

Un try/catch/finally fiable devra utiliser Régions d'exécution sous contrainte (CER) . Un site exemple est fourni par MSDN :

[StructLayout(LayoutKind.Sequential)]
struct MyStruct
{
    public IntPtr m_outputHandle;
}

sealed class MySafeHandle : SafeHandle
{
    // Called by P/Invoke when returning SafeHandles
    public MySafeHandle()
        : base(IntPtr.Zero, true)
    {
    }

    public MySafeHandle AllocateHandle()
    {
        // Allocate SafeHandle first to avoid failure later.
        MySafeHandle sh = new MySafeHandle();

        RuntimeHelpers.PrepareConstrainedRegions();
        try { }
        finally
        {
            MyStruct myStruct = new MyStruct();
            NativeAllocateHandle(ref myStruct);
            sh.SetHandle(myStruct.m_outputHandle);
        }

        return sh;
    }
}

L'article suivant constitue une excellente source d'information :

Meilleures pratiques en matière de fiabilité

0 votes

Pourriez-vous s'il vous plaît confirmer ce que vous avez dit sur ThreadAbortException non déclencheur finally ?

0 votes

Je suis d'accord, je suis presque sûr que ThreadAbortException tente d'exécuter le bloc final. Il favorise le bloc finally plutôt que d'abandonner réellement le thread, donc le second est moins garanti que le premier.

0 votes

@Steven Sudit, @David : Désolé, je n'avais probablement pas raison sur ce point. Je m'en doutais un peu, mais MSDN indique clairement que finally sera exécuté.

5voto

Leniel Macaferi Points 38324

De MSDN try-finally (Référence C#)

Le bloc finally est utile pour nettoyer les ressources allouées dans le bloc le bloc try ainsi que pour exécuter tout code qui doit s'exécuter même s'il y a une exception. Le contrôle est toujours transmis au bloc finally, quelle que soit de la façon dont le bloc try sort .

4voto

Ian Jacobs Points 4165

56 votes

7 votes

@IvanZlatanov La réponse est correcte dans le contexte de la question, dans laquelle le PO veut apparemment savoir si finally s'exécutera même après une déclaration de retour, cependant vous avez raison qu'il y a des circonstances dans lesquelles finally ne s'exécutera pas.

1 votes

Oh, vous seriez surpris. Regardez ça : static int Main( string[] arguments ) { try { return arguments[1000].Length ; } finally { System.Console.WriteLine( "vous ne verrez jamais ça !" ) ; } }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X