29 votes

VB.NET Try Catch avec plusieurs blocs Catch

Il s'agit d'une question vraiment étrange. Nous avons un Try Catch avec plusieurs blocs Catch. Le premier bloc Catch ne contient pas de code, juste un commentaire.

Try
  'Some Code
Catch ex As ThreadAbortException
  'Do Nothing
Catch ex As Exception
  HandleException(ex)
End Try

Si une exception autre qu'une ThreadAbortException est levée, elle est rattrapée par le second Catch, comme prévu. Cependant, lorsque l'on parcourt le code dans VS2010, l'objet ex n'est rien dans ce cas. Jusqu'à présent, nous avons trouvé deux façons de "résoudre" ce problème.

Fixe 1 : Renommer la première variable d'exception.

Try
  'Some Code
Catch tex As ThreadAbortException
  'Do Nothing
Catch ex As Exception
  HandleException(ex)
End Try

Fixe 2 : Ajouter n'importe quelle ligne de code au premier bloc Catch.

Try
  'Some Code
Catch ex As ThreadAbortException
  Dim i As Integer = 1
Catch ex As Exception
  HandleException(ex)
End Try

Le code dans HandleException semble toujours fonctionner correctement s'il est exécuté dans l'un des cas susmentionnés. S'agit-il d'un bogue dans Visual Studio ou dans le débogueur ? Ou est-ce que quelque chose nous échappe et que le premier bloc de code ci-dessus n'est pas valide ?

Tout cela se fait en .NET 4.0.

18voto

Konrad Rudolph Points 231505

Teejay a la bonne réponse.

Toutefois, si votre Catch est vide, la gestion de cette exception n'a aucun sens. Vous voulez juste éviter que le dernier bloc ne l'attrape. Vous peut utilisez votre méthode - mais considérez que le fait d'avoir une Catch est normalement inacceptable : les exceptions ne doivent pas être capturées ou doivent être gérées correctement ; les avaler silencieusement doit être considéré comme un bogue. Votre cas est une exception à cette règle mais, en tant que tel, il doit être documenté dans le code car, sinon, il embrouillera les mainteneurs attentifs.

Eh bien, VB dispose d'un idiome spécial pour cette situation :

Try
    ' …
Catch ex As Exception When Not TypeOf ex Is ThreadAbortException
    ' Only executed if `ex` isn’t a ThreadAbortException
End Try

Ce code n'attrape pas ThreadAbortException du tout, ce qui est la bonne chose à faire si vous ne voulez pas vous en occuper : ThreadAbortException ne peut pas est avalé, de sorte que même si vous l'attrapez, il sera relancé à la fin de l'opération. Catch bloc.

Notez que ceci est fondamentalement différent de la réponse de SysDragon qui utilise une méthode conventionnelle de If alors que le code utilisé ici utilise une clause spéciale dans l'instruction Catch comme filtre.

6voto

Teejay Points 2354

Il semble qu'il s'agisse d'un bug du débogueur de VS.

PREUVE

Si vous écrivez :

Try
    Throw New InvalidOperationException("MESSAGE")
Catch ex As ArgumentException
    'Do Nothing
Catch ex As Exception
    Debug.WriteLine(ex)
End Try

et vous regardez ex il est évalué à Nothing en Mode Quickwatch

MAIS

dans la console, le programme imprime correctement System.InvalidOperationException: MESSAGE

-2voto

jforward5 Points 10

Ok, laissez-moi développer...

Il semble que vous deviez avoir un "résultat" pour chaque prise. Si vous voulez simplement qu'il ne se passe rien pour une capture spécifique, ne l'incluez pas, ou déplacez-la à un autre endroit de votre code.

Try
   'Some Code
Catch ex As ThreadAbortException
   'Do something(ex: HandleExceptionSub())
Catch ex As Exception
   HandleException(ex)
End Try

Si vous "attrapez" une exception, vous devez en faire quelque chose.

EDIT :

J'ai également trouvé ces informations qui peuvent vous aider à mieux comprendre le fonctionnement d'une prise d'essai :

Blocs de capture multiples

Un bloc try peut générer plusieurs exceptions, qui peuvent être gérées en utilisant plusieurs blocs catch. N'oubliez pas qu'un bloc catch plus spécialisé doit précéder un bloc catch généralisé. Dans le cas contraire, le compilateur affichera une erreur de compilation. Blocs de capture multiples

Il ne s'agit pas d'un "bug" du débogueur. Le débogueur est censé vous aider à trouver et à gérer toutes les exceptions.

EDIT : Il semble que cette exception pourrait être évitée complètement d'après ce que j'ai lu dans un autre post. Et il semble qu'il serait préférable d'éviter l'exception plutôt que de ne pas la traiter. Gestion de l'exception ThreadAbortException

EDIT : Je viens de trouver plus d'informations sur les blocs de capture multiples dans le try. Cela vient de MSDN et indique qu'un bloc catch après un bloc catch vide ne sera jamais atteint... Try Catch Finally Statement Une preuve supplémentaire qu'il ne s'agit PAS d'un bogue, mais de la fonctionnalité attendue pour imposer le traitement de toutes les exceptions dans votre code.

EDIT : Pour mettre au clair certaines personnes dans les commentaires, j'ai créé un programme de test très simple pour voir s'il s'agit bien d'un bogue. Je constate que les blocs catch fonctionnent parfaitement. Il semble que le fait de suivre la méthode documentée par MSDN pour créer un Try Catch avec plusieurs blocs Catch fonctionne comme ils le disent.

    private void button1_Click(object sender, EventArgs e)
    {
        try
        {
            if (textBox1.Text == "")
            {
                throw new ArgumentNullException("textBox1", "TextBox can not be empty");
            }
            else
            {
                MyString(textBox1.Text);
            }
        }
        catch (ArgumentNullException ex)
        {
            //nothing
        }
        catch (Exception ex)
        {
            MessageBox.Show("Test: " + ex.Message);
        }
    }

    private int MyString(string text)
    {
        return int.Parse(text);
    }

J'ai créé un formulaire simple avec un bouton et une zone de texte. Si la boîte de texte est vide, je lance une exception ArgumentNullException, et dans "MyString", j'analyse une chaîne en un nombre entier, ce qui lance une exception FormatException. Le fait d'avoir un bloc catch vide, qui n'est PAS la bonne façon de gérer une exception "attrapée", fonctionne effectivement. Pour autant que je sache, il ne s'agit donc pas d'un bogue. Apparemment, la seule chose sur laquelle je suis d'accord avec Teejay et Konrad est que vous ne pouvez PAS attraper et gérer l'exception ThreadAbortException en utilisant la méthode try catch. La solution de Konrad est la meilleure façon de coder votre try catch.

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