为什么.NET异常没有被try / catch块捕获? [英] Why is .NET exception not caught by try/catch block?

查看:186
本文介绍了为什么.NET异常没有被try / catch块捕获?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用C#的 ANTLR 解析器库开发一个项目。我已经建立了一个语法来解析一些文本,它的效果很好。但是,当解析器遇到非法或意外的令牌时,它会抛出许多异常之一。问题是在某些情况下(不是全部)我的try / catch块不能捕获它,而是停止执行作为一个未处理的异常。



我的问题是我无法复制这个问题在其他地方,但在我的完整的代码。调用堆栈显示异常绝对发生在我的try / catch(异常)块中。我唯一可以想到的是,有几个ANTLR汇编调用发生在我的代码和代码抛出异常之间,这个库没有启用调试,所以我无法通过它。我想知道不可调试的程序集是否阻止异常冒泡?调用堆栈看起来像这样;外部程序集调用位于Antlr.Runtime中:

 
Expl.Itinerary.dll!TimeDefLexer.mTokens()行1213 C#
Antlr3 .Runtime.dll!Antlr.Runtime.Lexer.NextToken()+ 0xfc bytes
Antlr3.Runtime.dll!Antlr.Runtime.CommonTokenStream.FillBuffer()+ 0x22c bytes
Antlr3.Runtime.dll!Antlr .Runtime.CommonTokenStream.LT(int k = 1)+ 0x68 bytes
Expl.Itinerary.dll!TimeDefParser.prog()行109 + 0x17 bytes C#
Expl.Itinerary.dll!Expl.Itinerary。第17行+ 0xa字节C#



  try {
/ /执行停止在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);对于我来说,一个catch(Exception)子句应该捕获任何异常。 。有没有什么理由不会?



更新:我通过反射器跟踪外部程序集,没有发现任何线程的迹象。该组件似乎只是ANTLR生成的代码的运行时实用程序类。抛出的异常来自TimeDefLexer.mTokens()方法,其类型为NoViableAltException,它来自RecognitionException - > Exception。当词法分析器无法理解流中的下一个令牌时,会抛出此异常;换句话说,无效输入。这个异常被支持发生,但是它应该被我的try / catch块捕获。



此外,重新抛出ParserException与这种情况无关。这是一个抽象层,在解析过程中会遇到任何异常,并转换为我自己的ParserException。我遇到的异常处理问题从来没有达到这一行代码。事实上,我评论了抛出新的ParserException部分,仍然收到相同的结果。



还有一件事,我修改了原来的try / catch块而是捕获NoViableAltException,消除任何继承混淆。我仍然收到相同的结果。



有人曾经建议有时VS在调试模式下捕获处理异常时会过度活跃,但这个问题在发布模式下也会发生。 p>

男人,我还是傻了!我以前没有提到过,但我正在运行VS 2008,我的所有代码都是3.5。外部组件为2.0。另外,我的一些代码在2.0程序集中分类一个类。版本不匹配会导致此问题?



更新2:我可以通过移植相关部分来消除.NET版本冲突。 NET 3.5代码到.NET 2.0项目并复制相同的方案。我能够在.NET 2.0中一贯运行时复制相同的未处理的异常。



我了解到ANTLR最近发布了3.1。所以,我从3.0.1升级并重试。事实证明,生成的代码有点重构,但在我的测试用例中发生了相同的未处理异常。



更新3:
我已经在简化的VS 2008项目中复制了这种情况。随时自行下载并检查项目。我已经应用了所有伟大的建议,但还没有能够克服这个障碍。



如果您可以找到解决方法,请分享您的发现。再次感谢!






谢谢,但VS 2008自动中断未处理的异常。另外,我没有Debug-> Exceptions对话框。抛出的NoViableAltException是完全意图的,旨在被用户代码所捕获。因为它没有像预期那样被捕获,所以程序执行意外地作为一个未处理的异常中止。



抛出的异常是从Exception导出的,并没有多线程与ANTLR

解决方案

我相信我明白了这个问题。异常被捕获,这个问题在调试器的行为和每个尝试重新设置的人之间的差异中是混乱的。



我相信你得到以下消息:NoViableAltException被用户代码未处理和一个看起来像这样的callstack:

 
[外部代码]
> TestAntlr-3.1.exe!TimeDefLexer.mTokens()行852 + 0xe字节C#
[外部代码]
TestAntlr-3.1.exe!TimeDefParser.prog()行141 + 0x14字节C#
TestAntlr-3.1.exe!TestAntlr_3._1.Program.ParseTest(string Text =foobar;)行49 + 0x9字节C#
TestAntlr-3.1.exe!TestAntlr_3._1.Program。 Main(string [] args = {string [0x00000000]})行30 + 0xb字节C#
[外部代码]

如果您右键单击callstack窗口并运行打开显示外部代码,您可以看到:

 
Antlr3.Runtime.dll!Antlr.Runtime.DFA.NoViableAlt(int s = 0x00000000,Antlr.Runtime.IIntStream input = {Antlr.Runtime.ANTLRStringStream})+ 0x80 bytes
Antlr3.Runtime.dll !Antlr.Runtime.DFA.Predict(Antlr.Runtime.IIntStream input = {Antlr.Runtime.ANTLRStringStream})+ 0x21e bytes
> TestAntlr-3.1.exe!TimeDefLexer.mTokens()行852 + 0xe bytes C#
Antlr3.Runtime.dll!Antlr.Runtime.Lexer.NextToken()+ 0xc4 bytes
Antlr3.Runtime.dll!Antlr.Runtime.CommonTokenStream.FillBuffer()+ 0x147 bytes
Antlr3.Runtime .dll!Antlr.Runtime.CommonTokenStream.LT(int k = 0x00000001)+ 0x2d bytes
TestAntlr-3.1.exe!TimeDefParser.prog()行141 + 0x14 bytes C#
TestAntlr-3.1.exe! TestAntlr_3._1.Program.ParseTest(string Text =foobar;)行49 + 0x9字节C#
TestAntlr-3.1.exe!TestAntlr_3._1.Program.Main(string [] args = {string [0x00000000] })行30 + 0xb个字节C#
[原文为Ma naged Transition]
[管理到本地转换]
mscorlib.dll!System.AppDomain.ExecuteAssembly(string assemblyFile,System.Security.Policy.Evidence assemblySecurity,string [] args)+ 0x39 bytes
Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()+ 0x2b bytes
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state)+ 0x3b bytes
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext,System.Threading.ContextCallback callback,object state)+ 0x81 bytes
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x40字节

调试器的消息告诉您,代码(来自NoViableAlt)之外的异常正在通过TestAntlr中拥有的代码-3.1.exe!TimeDefLexer.mTokens()没有被处理。



这个措辞令人困惑,但这并不意味着这个例外是未知的。调试器让你知道你拥有mTokens()的代码需要对这个异常进行强制运行。



要玩的东西看看这个外观对于那些没有解决问题的人:




  • 转到工具/选项/调试,
    关闭启用我的代码
    (仅管理)或选项。

  • 转到调试器/异常,关闭
    常用语言运行时异常的用户未处理 / li>

I'm working on a project using the ANTLR parser library for C#. I've built a grammar to parse some text and it works well. However, when the parser comes across an illegal or unexpected token, it throws one of many exceptions. The problem is that in some cases (not all) that my try/catch block won't catch it and instead stops execution as an unhandled exception.

The issue for me is that I can't replicate this issue anywhere else but in my full code. The call stack shows that the exception definitely occurs within my try/catch(Exception) block. The only thing I can think of is that there are a few ANTLR assembly calls that occur between my code and the code throwing the exception and this library does not have debugging enabled, so I can't step through it. I wonder if non-debuggable assemblies inhibit exception bubbling? The call stack looks like this; external assembly calls are in Antlr.Runtime:

    Expl.Itinerary.dll!TimeDefLexer.mTokens() Line 1213 C#
    Antlr3.Runtime.dll!Antlr.Runtime.Lexer.NextToken() + 0xfc bytes 
    Antlr3.Runtime.dll!Antlr.Runtime.CommonTokenStream.FillBuffer() + 0x22c bytes   
    Antlr3.Runtime.dll!Antlr.Runtime.CommonTokenStream.LT(int k = 1) + 0x68 bytes
    Expl.Itinerary.dll!TimeDefParser.prog() Line 109 + 0x17 bytes   C#
    Expl.Itinerary.dll!Expl.Itinerary.TDLParser.Parse(string Text = "", Expl.Itinerary.IItinerary Itinerary = {Expl.Itinerary.MemoryItinerary}) Line 17 + 0xa bytes C#

The code snippet from the bottom-most call in Parse() looks like:

     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);
     }

To me, a catch (Exception) clause should've captured any exception whatsoever. Is there any reason why it wouldn't?

Update: I traced through the external assembly with Reflector and found no evidence of threading whatsoever. The assembly seems to just be a runtime utility class for ANTLR's generated code. The exception thrown is from the TimeDefLexer.mTokens() method and its type is NoViableAltException, which derives from RecognitionException -> Exception. This exception is thrown when the lexer cannot understand the next token in the stream; in other words, invalid input. This exception is SUPPOSED to happen, however it should've been caught by my try/catch block.

Also, the rethrowing of ParserException is really irrelevant to this situation. That is a layer of abstraction that takes any exception during parse and convert to my own ParserException. The exception handling problem I'm experiencing is never reaching that line of code. In fact, I commented out the "throw new ParserException" portion and still received the same result.

One more thing, I modified the original try/catch block in question to instead catch NoViableAltException, eliminating any inheritance confusion. I still received the same result.

Someone once suggested that sometimes VS is overactive on catching handled exceptions when in debug mode, but this issue also happens in release mode.

Man, I'm still stumped! I hadn't mentioned it before, but I'm running VS 2008 and all my code is 3.5. The external assembly is 2.0. Also, some of my code subclasses a class in the 2.0 assembly. Could a version mismatch cause this issue?

Update 2: I was able to eliminate the .NET version conflict by porting relevant portions of my .NET 3.5 code to a .NET 2.0 project and replicate the same scenario. I was able to replicate the same unhandled exception when running consistently in .NET 2.0.

I learned that ANTLR has recently released 3.1. So, I upgraded from 3.0.1 and retried. It turns out the generated code is a little refactored, but the same unhandled exception occurs in my test cases.

Update 3: I've replicated this scenario in a simplified VS 2008 project. Feel free to download and inspect the project for yourself. I've applied all the great suggestions, but have not been able to overcome this obstacle yet.

If you can find a workaround, please do share your findings. Thanks again!


Thank you, but VS 2008 automatically breaks on unhandled exceptions. Also, I don't have a Debug->Exceptions dialog. The NoViableAltException that is thrown is fully intended, and designed to be caught by user code. Since it is not caught as expected, program execution halts unexpectedly as an unhandled exception.

The exception thrown is derived from Exception and there is no multi-threading going on with ANTLR.

解决方案

I believe I understand the problem. The exception is being caught, the issue is confusion over the debugger's behavior and differences in the debugger settings among each person trying to repro it.

In the 3rd case from your repro I believe you are getting the following message: "NoViableAltException was unhandled by user code" and a callstack that looks like this:

         [External Code]    
    >   TestAntlr-3.1.exe!TimeDefLexer.mTokens() Line 852 + 0xe bytes   C#
        [External Code] 
        TestAntlr-3.1.exe!TimeDefParser.prog() Line 141 + 0x14 bytes    C#
        TestAntlr-3.1.exe!TestAntlr_3._1.Program.ParseTest(string Text = "foobar;") Line 49 + 0x9 bytes C#
        TestAntlr-3.1.exe!TestAntlr_3._1.Program.Main(string[] args = {string[0x00000000]}) Line 30 + 0xb bytes C#
        [External Code] 

If you right click in the callstack window and run turn on show external code you see this:

        Antlr3.Runtime.dll!Antlr.Runtime.DFA.NoViableAlt(int s = 0x00000000, Antlr.Runtime.IIntStream input = {Antlr.Runtime.ANTLRStringStream}) + 0x80 bytes   
        Antlr3.Runtime.dll!Antlr.Runtime.DFA.Predict(Antlr.Runtime.IIntStream input = {Antlr.Runtime.ANTLRStringStream}) + 0x21e bytes  
    >   TestAntlr-3.1.exe!TimeDefLexer.mTokens() Line 852 + 0xe bytes   C#
        Antlr3.Runtime.dll!Antlr.Runtime.Lexer.NextToken() + 0xc4 bytes 
        Antlr3.Runtime.dll!Antlr.Runtime.CommonTokenStream.FillBuffer() + 0x147 bytes   
        Antlr3.Runtime.dll!Antlr.Runtime.CommonTokenStream.LT(int k = 0x00000001) + 0x2d bytes  
        TestAntlr-3.1.exe!TimeDefParser.prog() Line 141 + 0x14 bytes    C#
        TestAntlr-3.1.exe!TestAntlr_3._1.Program.ParseTest(string Text = "foobar;") Line 49 + 0x9 bytes C#
        TestAntlr-3.1.exe!TestAntlr_3._1.Program.Main(string[] args = {string[0x00000000]}) Line 30 + 0xb bytes C#
        [Native to Managed Transition]  
        [Managed to Native Transition]  
        mscorlib.dll!System.AppDomain.ExecuteAssembly(string assemblyFile, System.Security.Policy.Evidence assemblySecurity, string[] args) + 0x39 bytes    
        Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() + 0x2b bytes  
        mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state) + 0x3b bytes   
        mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x81 bytes    
        mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x40 bytes

The debugger's message is telling you that an exception originating outside your code (from NoViableAlt) is going through code you own in TestAntlr-3.1.exe!TimeDefLexer.mTokens() without being handled.

The wording is confusing, but it does not mean the exception is uncaught. The debugger is letting you know that code you own mTokens()" needs to be robust against this exception being thrown through it.

Things to play with to see how this looks for those who didn't repro the problem:

  • Go to Tools/Options/Debugging and turn off "Enable Just My code (Managed only)". or option.
  • Go to Debugger/Exceptions and turn off "User-unhandled" for Common-Language Runtime Exceptions.

这篇关于为什么.NET异常没有被try / catch块捕获?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆