45 votes

Pourquoi est .NET exception n'est pas pris en bloc try/catch?

Je suis en train de travailler sur un projet à l'aide de la ANTLR bibliothèque de l'analyseur de C#. J'ai construit une grammaire pour analyser le texte et il fonctionne bien. Toutefois, lorsque l'analyseur est livré à travers illégales ou jeton inattendu, il jette l'une des nombreuses exceptions. Le problème est que dans certains cas (pas tous) que mon bloc try/catch ne s'y accroche et s'arrête au lieu de l'exécution d'une exception non gérée.

Le problème pour moi est que je ne peux pas reproduire ce problème n'importe où d'autre, mais dans mon code complet. La pile d'appel montre que l'exception certainement se produit à l'intérieur de mon try/catch(Exception) de bloc. La seule chose que je peux penser, c'est que il y a quelques ANTLR assemblée des appels qui se produisent entre mon code et le code de jeter l'exception et cette bibliothèque ne dispose pas de débogage activé, donc je ne peux pas l'étape à travers elle. Je me demande si la non-debuggable assemblées inhiber l'exception de bouillonnement? La pile d'appel ressemble à ceci; assembly externe les appels sont Antlr.Runtime:

 Expl.Itinerary.dll!TimeDefLexer.mTokens() de la Ligne de 1213 C#
 Antlr3.Runtime.dll!Antlr.Moment de l'exécution.Lexer.NextToken() + 0xfc octets 
 Antlr3.Runtime.dll!Antlr.Moment de l'exécution.CommonTokenStream.FillBuffer() + 0x22c octets 
 Antlr3.Runtime.dll!Antlr.Moment de l'exécution.CommonTokenStream.LT(int k = 1) + 0x68 octets
 Expl.Itinerary.dll!TimeDefParser.prog() de la Ligne 109 + 0x17 octets C#
 Expl.Itinerary.dll!Expl.L'itinéraire.TDLParser.Parse(string Texte = "", Expl.L'itinéraire.IItinerary Itinéraire = {Expl.L'itinéraire.MemoryItinerary}) Ligne 17 + 0xa octets C#

Le fragment de code dans le fond le plus appel dans Parse() ressemble à:

     try {
        // Execution stopped at parser.prog()
        TimeDefParser.prog_return prog_ret = parser.prog();
        return prog_ret == null ? null : prog_ret.value;
     }
     catch (Exception ex) {
        throw new ParserException(ex.Message, ex);
     }

Pour moi, un catch (Exception) de la clause devraient ai capturé exception aucune. Est-il une raison pourquoi il ne le serait pas?

Mise à jour: j'ai tracé par les externes de l'assemblée avec Réflecteur et n'a trouvé aucune preuve de filetage que ce soit. L'assemblée semble juste être un moteur d'exécution de l'utilitaire de classe pour ANTLR du code généré. L'exception est à partir de la TimeDefLexer.mTokens() la méthode et son type est NoViableAltException, qui dérive de RecognitionException -> Exception. Cette exception est levée lors de l'analyseur lexical ne peut pas comprendre le prochain jeton dans le cours d'eau; en d'autres termes, une entrée non valide. Cette exception est CENSÉ se produire, mais il devrait avez été surpris par mon bloc try/catch.

Aussi, le renvoi de ParserException est vraiment pas pertinent à cette situation. C'est une couche d'abstraction qui prend toute exception lors de l'analyser et de le convertir à ma propre ParserException. La gestion des exceptions de problème, je suis en train de vivre est de ne jamais atteindre cette ligne de code. En fait, j'ai commenté le "throw new ParserException" partie et encore reçu le même résultat.

Encore une chose, j'ai modifié l'original bloc try/catch dans la question de la place de capture NoViableAltException, l'élimination de tout l'héritage de la confusion. J'ai encore reçu le même résultat.

Quelqu'un a suggéré que, parfois, VS est hyperactive sur la capture exceptions traitées en mode débogage, mais ce problème se produit également en mode release.

L'homme, je suis toujours perplexe! Je n'avais pas parlé avant, mais je suis en cours d'exécution par rapport à 2008 et tout mon code est de 3,5. L'assembly externe est 2.0. Aussi, certains de mon code sous-classes d'une classe de l'2.0 assemblée. Pourrait une incompatibilité de version provoquer ce problème?

Mise à jour 2: j'ai été en mesure d'éliminer l' .NET version conflit par le portage de parties pertinentes de mon .NET 3.5 code pour une .NET 2.0 projet et de reproduire le même scénario. J'ai été en mesure de reproduire la même exception non gérée lors de l'exécution de manière cohérente dans .NET 2.0.

J'ai appris que ANTLR a récemment publié 3.1. Donc, j'ai mis à niveau à partir 3.0.1 et de tentative d'appel. Il s'avère que le code généré est un peu remaniée, mais la même exception non gérée se produit dans mon cas de test.

Mise à jour 3: J'ai répliqué ce scénario dans un simplifiées par rapport à 2008 projet. N'hésitez pas à télécharger et inspecter le projet pour vous-même. J'ai appliqué toutes les bonnes suggestions, mais n'ont pas été en mesure de surmonter cet obstacle encore.

Si vous pouvez trouver une solution, s'il vous plaît partagez vos découvertes. Merci encore!


Merci, mais VS 2008 automatiquement les pauses sur les exceptions non gérées. Aussi, je n'ai pas de Debug->boîte de dialogue Exceptions. Le NoViableAltException qui est jetée est entièrement destiné et conçu pour être attrapé par le code de l'utilisateur. Car il n'est pas pris comme prévu, l'exécution du programme s'arrête de façon inattendue comme une exception non gérée.

L'exception est dérivé de l'Exception et il n'y a pas de multi-threading passe avec ANTLR.

30voto

Steve Steiner Points 4044

Je crois que je comprends le problème. L'exception est d'être pris, le problème est la confusion avec le débogueur du comportement et des différences dans les paramètres du débogueur entre chaque personne essayant de repro il.

Dans le 3ème cas de votre repro je crois que vous obtenez le message suivant: "NoViableAltException a été gérée par le code de l'utilisateur" et une pile des appels qui ressemble à ceci:

 [Externe Code] 
 > TestAntlr-3.1.exe!TimeDefLexer.mTokens() de la Ligne de 852 + 0xe octets C#
 [Externe Code] 
 TestAntlr-3.1.exe!TimeDefParser.prog() de la Ligne 141 + 0 x 14 octets C#
 TestAntlr-3.1.exe!TestAntlr_3._1.Programme.ParseTest(string Texte = "foobar;") de la Ligne 49 + 0x9 octets C#
 TestAntlr-3.1.exe!TestAntlr_3._1.Programme.Main(string[] args = {string[0 x 00000000]}) Ligne 30 + 0xb octets C#
 [Externe Code] 

Si vous faites un clic droit dans la fenêtre de la pile et de l'exécuter à son tour sur le spectacle d'un code externe, vous voyez ceci:

 Antlr3.Runtime.dll!Antlr.Moment de l'exécution.DFA.NoViableAlt(int s = 0 x 00000000, Antlr.Moment de l'exécution.IIntStream entrée = {Antlr.Moment de l'exécution.ANTLRStringStream}) + 0x80 octets 
 Antlr3.Runtime.dll!Antlr.Moment de l'exécution.DFA.Prévoir(Antlr.Moment de l'exécution.IIntStream entrée = {Antlr.Moment de l'exécution.ANTLRStringStream}) + 0x21e octets 
 > TestAntlr-3.1.exe!TimeDefLexer.mTokens() de la Ligne de 852 + 0xe octets C#
 Antlr3.Runtime.dll!Antlr.Moment de l'exécution.Lexer.NextToken() + 0xc4 octets 
 Antlr3.Runtime.dll!Antlr.Moment de l'exécution.CommonTokenStream.FillBuffer() + 0x147 octets 
 Antlr3.Runtime.dll!Antlr.Moment de l'exécution.CommonTokenStream.LT(int k = 0 x 00000001) + 0x2d octets 
 TestAntlr-3.1.exe!TimeDefParser.prog() de la Ligne 141 + 0 x 14 octets C#
 TestAntlr-3.1.exe!TestAntlr_3._1.Programme.ParseTest(string Texte = "foobar;") de la Ligne 49 + 0x9 octets C#
 TestAntlr-3.1.exe!TestAntlr_3._1.Programme.Main(string[] args = {string[0 x 00000000]}) Ligne 30 + 0xb octets C#
 [Native pour la gestion de la Transition] 
 [Gérés Natif de Transition] 
 mscorlib.dll!Système.Domaine d'application.ExecuteAssembly(string assemblyFile, Système.De sécurité.Politique.La preuve assemblySecurity, string[] args) + 0x39 octets 
 Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() + 0x2b octets 
 mscorlib.dll!Système.Le filetage.ThreadHelper.ThreadStart_Context(état de l'objet) + 0x3b octets 
 mscorlib.dll!Système.Le filetage.ExecutionContext.Exécuter(Système D'.Le filetage.ExecutionContext executionContext, Système.Le filetage.Rappel ContextCallback, état de l'objet) + 0 x 81 octets 
 mscorlib.dll!Système.Le filetage.ThreadHelper.ThreadStart() + 0 x 40 octets

Le débogueur message vous indique qu'une exception provenant de l'extérieur de votre code (à partir de NoViableAlt) est de passer par le code que vous possédez TestAntlr-3.1.exe!TimeDefLexer.mTokens() sans être traitées.

La formulation prête à confusion, mais il ne signifie pas que l'exception est interceptée. Le débogueur est de laisser vous savez que le code que vous possédez mTokens()" doit être robuste à l'encontre de cette exception levée par elle.

Choses à jouer avec pour voir à quoi cela ressemble pour ceux qui n'ont pas reproduire le problème:

  • Allez dans Outils/Options/Débogage et désactiver l'option "Activer uniquement Mon code (Gérée uniquement)". ou une option.
  • Aller à Debugger/Exceptions et éteindre "l'Utilisateur-non gérée" pour Common Language Runtime Exceptions.

8voto

ljs Points 16511

Indépendamment de savoir si l'assemblée a été compilé en release construire l'exception devrait certainement "bulle" jusqu'à l'appelant, il n'y a aucune raison pour laquelle une assemblée de ne pas être compilé en mode debug devrait avoir une incidence sur les que.

Je serai d'accord avec Daniel, ce qui suggère que peut-être l'exception est survenue sur un thread séparé - essayez de brancher le fil d'événements d'exception dans l'Application.ThreadException. Cela devrait être soulevée lors de la non gérées fil exception se produit. Vous pouvez alors adapter votre code ainsi:-

using System.Threading;

...

void Application_ThreadException(object sender, ThreadExceptionEventArgs e) {
  throw new ParserException(e.Exception.Message, e.Exception);
}    

 ...

 var exceptionHandler = 
    new ThreadExceptionEventHandler(Application_ThreadException);
 Application.ThreadException += exceptionHandler;
 try {
    // Execution stopped at parser.prog()
    TimeDefParser.prog_return prog_ret = parser.prog();
    return prog_ret == null ? null : prog_ret.value;
 }
 catch (Exception ex) {
    throw new ParserException(ex.Message, ex);
 }
 finally {
    Application.ThreadException -= exceptionHandler;
 }

5voto

tbreffni Points 3031

Êtes-vous à l'aide .Net 1.0 ou 1.1? Si oui, alors catch(Exception ex) ne sera pas attraper les exceptions de code non managé. Vous aurez besoin d'utiliser catch {} à la place. Voir cet article pour plus de détails:

http://www.netfxharmonics.com/2005/10/net-20-trycatch-and-trycatchexception/

3voto

Daniel Auger Points 8459

Est-il possible que l'exception est levée dans un autre thread? Evidemment, votre code d'appel est mono-thread, mais peut-être que la bibliothèque de l'automate est en train de faire quelques multithread opérations de sous les couvertures.

3voto

Luke Girvin Points 8270

Pourriez-vous traiter avec une exception qui ne découle pas de Système.Exception? Si donc voir cet article MSDN:

http://msdn.microsoft.com/en-us/library/ms404228(SV.80).aspx

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