1
votes

Pourquoi le bloc finally peut ne pas s'exécuter lorsque l'exception est levée?

Pendant longtemps j'ai pensé que cela me permettait de libérer toutes les ressources du bloc finally et j'ai pensé que si une exception se produisait dans le bloc try , alors les ressources seront toujours libérées dans le bloc enfin . Mais cela ne semble pas être le cas.

J'ai le morceau de code suivant:

using System;

public sealed class Program
{

    public static void Main()
    {
            int zero = 0;
            int i = 1/zero;

            Console.WriteLine("divide by zero"); //the line is never called
    }
}

Je n'atteins jamais la ligne qui s'imprime sur la console. Cela signifie que je ne pourrai pas libérer de ressources dans le bloc finally dans ce cas sur l'exception lancée à l'intérieur du bloc try .

Donc , Je crois qu'il y a deux choses: soit il me manque quelque chose, soit la combinaison try + finally n'a pas de cas d'utilisation dans le C #. La deuxième déclaration a du sens, car j'obtiendrai la même fonctionnalité que celle produite par le code ci-dessus avec le code ci-dessous:

using System;

public sealed class Program
{

    public static void Main()
    {
        try {
            int zero = 0;
            int i = 1/zero;
        } finally {
            Console.WriteLine("divide by zero"); //the line is never called
        }
    }
}

Mais j'ai peur de manquer quelque chose ici. Alors, quelqu'un pourrait-il confirmer que la combinaison est inutile ou prouver qu'elle ne l'est pas, s'il vous plaît?

MISE À JOUR

Après le commentaire qui peut appeler le enfin bloc dans son violon, j'ai vérifié une fois de plus dans le code VS, et je ne vois toujours pas de sortie.

 entrez la description de l'image ici p>


10 commentaires

@MichaelRandall Essayez avec le compilateur .NET Core: dotnetfiddle.net/8hLq8h


@JohnathanBarclay, oh. Tu es mon sauveur. Cela est dû à la transition .NET Core, alors que je suis habitué au .NET Framework. Merci beaucoup.


@JohnathanBarclay, je pense que votre commentaire est la réponse que je cherchais. Pourriez-vous, s'il vous plaît, l'ajouter comme réponse?


Est-ce que cela répond à votre question? C # essayez d'attraper la confusion


@ T.S., Non. Ce qui répond à mes questions, c'est le violon de Johnathan Barclay .


@qqqqqqq La réponse de Michael Randall explique la véritable raison. Mon violon n'était qu'une observation.


@JohnathanBarclay, je ne peux pas déduire de la réponse ce qui est si différent du .NET Core du .NET Framework qui a conduit à un tel comportement. C'est crucial pour ma question.


J'ai réécrit un titre très large / basé sur une opinion - si vous pensez que la modification ne reflète pas ce que vous demandez (c'est aussi exactement ce qui est répondu / accepté), n'hésitez pas à edit plus, mais ne revenez pas au style de titre" Quels sont tous les cas d'utilisation possibles… ".


@JohnathanBarclay, pourriez-vous, s'il vous plaît, me faire savoir quel était votre chemin de déduction que vous avez décidé de vérifier le .NET Core? Était-ce une décision aléatoire?


Pas de processus de réflexion; Je teste généralement tout dans. NET Core maintenant et j'ai observé le même comportement que vous.


4 Réponses :


8
votes

Vos hypothèses sont incorrectes (parfois) https://dotnetfiddle.net/hjqmOS

try-finally (référence C #)

En utilisant un bloc finally, vous pouvez nettoyer toutes les ressources alloué dans un bloc try, et vous pouvez exécuter du code même si une exception se produit dans le bloc try. En règle générale, les instructions d'un bloc finally s'exécute lorsque le contrôle quitte une instruction try. Le transfert de contrôle peut se produire à la suite d'une exécution normale, de l'exécution d'une pause, instruction continue, goto ou return, ou de propagation d'une exception hors de l'instruction try.

Il y a des cas où il ne s'exécute pas

Dans une exception gérée, le bloc finally associé est garanti être exécuté. Cependant, si l'exception n'est pas gérée, l'exécution du Enfin, le bloc dépend de la façon dont l'opération de déroulement de l'exception est déclenché . Cela dépend à son tour de la configuration de votre ordinateur.

Voici la partie importante

Habituellement, lorsqu'une exception non gérée met fin à une application, que pas le dernier bloc est exécuté n'est pas important. Cependant, si vous avez instructions dans un bloc finally qui doit être exécuté même dans cette situation, une solution consiste à ajouter un bloc catch à l'instruction try-finally. Vous pouvez également intercepter l'exception qui pourrait être levée dans le try block d'une instruction try-finally plus haut dans la pile d'appels.


8 commentaires

Wow .. n'avait aucune idée de la mise en garde dans la dernière citation. Cela semble un peu contre-intuitif ... mais encore une fois, je ne pense pas avoir jamais eu besoin de lire la documentation pour essayer / attraper (ou c'est ce que j'ai pensé!).


@BrootsWaymb c'est surprenant ce qui est enfoui dans ces documentations embêtantes :)


@MichaelRandall, cela signifie-t-il que le dernier devis de documentation est pris en charge par le .NET Core, mais pas par le .NET Framework?


@qqqqqqq en bref, utilisez un catch-finally pour gérer les exceptions pour essayer de vous assurer que quelque chose est exécuté. Ne dépendez pas de l'environnement


@MichaelRandall, compris. Merci. Pourriez-vous, s'il vous plaît, me faire savoir ce que signifie le déclenchement de l'opération de déroulement d'exception ? Je n'ai pas pu trouver quoi que ce soit expliquant cela dans la documentation.


@MichaelRandall, encore une chose que je trouve déroutante, c'est que nous avons le en utilisant en C #. Le using imite le try + enfin. Alors, est-il naturel d'attendre le même genre de problèmes de l'utilisation? (Je ne m'attends pas à ce que vous connaissiez la réponse, probablement quelqu'un d'autre pourra y répondre). Merci encore une fois.


@qqqqqqq hrm " deviner " cela dépend du système d'exploitation et de la façon dont il déroule la pile. Mais peut-être que quelqu'un avec un peu plus de connaissances sur les éléments internes peut répondre à cette question. C'est probablement une autre question, et intéressante en plus, qui pourrait attirer des personnes comme quelqu'un avec un peu plus de connaissances.


@MichaelRandall, merci vous .



1
votes

try / catch / finally n'a rien à voir avec la libération de ressources. Il s'agit strictement du flux d'application et de la construction de gestion des erreurs. Vous vivez dans le code managé et le garbage collector libère des ressources. Cette construction fait ce qui suit

try
{
    int zero = 0;
    int i = 1/zero;
}
catch (DividedByZeroException ex)
{
    Console.WriteLine(Exception handled);
    throw; // propagate ex to caller
}
finally
{
    Console.WriteLine("Method ended execution"); // called with or without exception
}


4 commentaires

@qqqqqqq Si T.S. a voté pour le double, et deux autres ont voté pour hors sujet, cela compterait le vote de T.S. pour la clôture hors sujet.


@JonathonChase, oh. Encore une information utile. Merci.


@ T.S., Mes excuses. Il semble que mon accusation soit due à mon manque de connaissances.


@qqqqqqq Par ailleurs, le commentaire "Est-ce que cela répond à votre question?" est ajouté automatiquement par le système sur mon comportement.



1
votes

Je crois que c'est parce que vous avez VS pour casser les erreurs non gérées et donc VS étapes pour afficher l'exception. Si vous le compilez et l'exécutez manuellement sur la ligne de commande, je crois que vous verrez "diviser par zéro". De plus, au lieu de modifier vos paramètres VS, vous pouvez «gérer» l'erreur et vous devriez alors voir le comportement que vous attendez.

Exemple:

using System;

public sealed class Program
{

public static void Main()
{
    try
    {
        int zero = 0;
        int i = 1 / zero;
    }
    catch
    {

    }
    finally
    {
        Console.WriteLine("divide by zero"); 
    }
}
}


1 commentaires

Ouais. Je vois la sortie avec le bloc catch ajouté. Merci.



0
votes

Je voudrais partager l'extrait suivant du livre C # via CLR , qui m'a expliqué pourquoi le bloc enfin ne peut pas être appelé.

Si une exception est levée par le code s'exécutant dans le bloc try (ou toute méthode appelée à partir du bloc try), le CLR commence à rechercher des blocs catch dont le type catch est du même type que ou a type de base de l'exception levée. Si aucun des types de capture ne correspond à l'exception, le CLR continue recherche dans la pile d'appels à la recherche d'un type de capture qui correspond à l'exception. Si après avoir atteint le en haut de la pile d'appels, aucun bloc catch n'est trouvé avec un type catch correspondant, une exception non gérée se produit.

Une fois que le CLR a localisé un bloc catch avec un type catch correspondant, il exécute le code dans tous les Enfin les blocs, en commençant par le bloc try dont le code a levé l'exception et en s'arrêtant avec le bloc catch correspondant à l'exception. Notez que tout bloc finally associé à la Le bloc catch correspondant à l'exception n'est pas encore exécuté. Le code de ce bloc final ne sera pas s'exécute jusqu'à ce que le code du bloc catch de gestion soit exécuté.

Une fois que tout le code dans les blocs finally internes a été exécuté, le code dans le bloc catch de gestion s'exécute.

Donc, cela signifie qu'en cas d'exception non gérée, le bloc finalement ne sera pas appelé.


0 commentaires