前几天,有一个朋友问我为什么在.NET里不能捕捉(catch)到一些异常了,而且在调试器里也捕捉不到。研究了一下,是.NET 4.0里新的异常处理机制捣的鬼。
在.NET 4.0之后,CLR将会区别出一些异常(都是SEH异常),将这些异常标识为破坏性异常(Corrupted State Exception)。针对这些异常,CLR的catch块不会捕捉这些异常,即使你用类似下面的代码:
以下是引用片段: try { TestMethod(); } catch (Exception e) { Console.WriteLine(“Catching exception: {0}”, e); } |
也没有办法捕捉到这些异常。之所以要这样设计,在MSDN的文章Handling Corrupted State Exceptions里已经提到了。即,有一些支持插件的程序,例如Visual Studio或者SQL Server,它们支持调用托管代码编写成的插件,但是它们自己本身有很多代码是由非托管的C++写成的。由于插件经常会调用到非托管的API,而很多时间,这些插件的代码根本就不知道如何处理非托管的API抛出来的SEH异常。在4.0以前,因为SEH异常被转换成了跟普通.NET异常相同的异常,这样程序员只要用catch ( Exception e)的模式就可以捕捉到所有的异常。这样处理的问题是,由于SEH异常通常都不是托管代码抛出的,托管代码根本就不知道SHE异常被扔出来的原因,简单的catch ( Exception e)处理使得整个程序会处于一个非常不稳定的状态,使得前面被忽略的问题在后面以更严重的方式出现 — 例如保存被破坏的数据。这样,看起来使用catch ( Exception e)处理所有的异常的方法很简单,但实际上让程序员或者用户在问题延后发生时,分析起来需要花费更多的精力。
因此在4.0以后,大部分SHE(我怀疑是所有)异常都被标识成破坏性异常,在.NET里,默认情况下CLR不会捕捉它们,而是任由操作系统来处理—即关闭程序,并打开一个错误对话框通知用户。为了保证兼容性,在4.0以前编译的程序,例如在2.0、3.0和3.5编译的程序,依然采用的是老的策略—即.NET会同时捕捉.NET异常和SHE异常。而在4.0下面编译的程序才会使用新的策略,这也是在文章的开头,我的朋友所碰到的问题。你可以在.NET 4.0下面编译下面的程序,体验一下这个新变化:
以下是引用片段: Program.cs using System; using System.Runtime.InteropServices; namespace ConsoleApplication1 { class Program { [DllImport(“Ref.dll”)] private extern static void TestMethod(); static void Main(string[] args) { try { TestMethod(); } catch (Exception e) { Console.WriteLine(“Catching exception: {0}”, e); } } } } Ref.cpp: #include “stdafx.h” extern “C” __declspec(dllexport) void TestMethod() { int *p = NULL; // 会导致.NET抛出一个AccessViolation异常 *p = 10; } |
上面的代码里,Program.cs使用P/Invoke技术调用了Ref.dll文件里的TestMethod,但是TestMethod尝试给一个空指针赋值,导致一个AccessViolation异常。如果你在2.0下面编译program.cs,并执行的话,这个AccessViolation异常会被catch(Exception e)捕捉到,而如果你在4.0下面编译并执行的话,你会发现catch (Exception e)是不能捕捉到这个异常的。
然而并不是所有人都想要这个新的异常机制,如果你的程序是在4.0下面编译并运行,而你又想在.NET程序里捕捉到SHE异常的话,有两个方案可以尝试:
1.在托管程序的.config文件里,启用legacyCorruptedStateExceptionsPolicy这个属性,即简化的.config文件类似下面的文件:
以下是引用片段: App.config: <?xml version=”1.0″?> <configuration> <startup> <supportedRuntime version=”v4.0″ sku=”.NETFramework,Version=v4.0″/> </startup> <runtime> <legacyCorruptedStateExceptionsPolicy enabled=”true” /> </runtime> </configuration> |
这个设置告诉CLR 4.0,整个.NET程序都要使用老的异常捕捉机制。
2.在需要捕捉破坏性异常的函数外面加一个HandleProcessCorruptedStateExceptions属性,这个属性只控制一个函数,对托管程序的其他函数没有影响,例如:
以下是引用片段: [HandleProcessCorruptedStateExceptions] static void Main(string[] args) { try { TestMethod(); } catch (Exception e) { Console.WriteLine(“Catching exception: {0}”, e); } } |
你也可以下载示例代码自己试一下(需要VS 2010才能编译):
http://files.cnblogs.com/killmyday/CSEsample.zip
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
TechTarget
官方微博
TechTarget中国
作者
相关推荐
-
.NET架构师:函数式语言做领域驱动设计
Scott一位.NET架构师,同时也是掌握函数式编程的作者,他很欣赏函数式编程,对于Scott来说,面向对象编程的那些概念也很恐怖,比如多态、泛型、继承、协变等。
-
软件开发就像炒股 关键看你怎么选股票!
本文作者Paulo Ortins在这里分享了对于选择哪种编程语言作为软件开发工作的起点的话题,并阐述了自己的观点。
-
增进离岸Java开发效率的十个提示
近日,Cygnet Infotech公司发布了一篇博文,谈到了如何增进离岸Java开发的效率。众多的ISV与软件厂商总是在不断寻找能以最低的代价实现其业务目标的解决方案。
-
Visual Studio 2013增强调试功能
Visual Studio 2013包含了若干诊断特性,能够帮助开发人员有效地调试他们的应用程序。