我有一个简单的try-catch-finally代码块,它在.NET3.5中按预期工作,但在使用.NET4.5.1创建的项目中,相同的代码表现完全不同.基本上,在.NET4.5.1中,如果发生异常而不是我在try-catch-finally块中预期的行为,则"finally"块不会被命中.我试过不同的机器,我的另外两个同事也在尝试,我们都得到了相同的结果.这对我来说很关心,因为我使用finally块来关闭DataReader,某些连接以及诸如此类的东西.
如果在没有调试器的RELEASE模式下抛出异常或运行RELEASE编译的EXE文件时,.NET4.5.1不会触发"finally"块.在调试模式下,两个.NET版本都达到了"finally"块.
同样,下面的代码在.NET3.5 RELEASE模式下没有调试器但在.NET4.5.1中没有表现.我错过了什么吗?有人可以帮忙吗?
class Program
{
static void Main(string[] args)
{
try
{
string a = null;
var x = a.Length;
Console.WriteLine(x);
}
catch (Exception ex)
{
throw;
}
finally
{
Console.WriteLine("This is the finally block.");
}
Console.WriteLine("You should not be here if an exception occured!");
}
}
Run Code Online (Sandbox Code Playgroud)
Eri*_*ert 19
下面的代码在.NET3.5 RELEASE模式下没有调试器但在.NET4.5.1中没有表现.我错过了什么吗?
注意:我夸大了这种行为的未定义水平; 感谢评论员Voo指出这一点.我应该首先回到规范.
是.CLI规范要求CLR在存在未处理的异常时结束程序.如果处理异常,则只需要运行finally块.对于在存在未处理的异常时是否需要,允许或不允许执行最终块的问题,规范是模糊的; 然后安全的假设是说这是规范未定义的行为,这取决于特定的实现.
CLR可以随心所欲地选择是否运行最终块来处理未处理的异常.许多人认为CLR使用这种算法:在异常时,走向调用堆栈,随后执行finally块,寻找处理程序; 如果未找到处理程序,则终止该进程.CLR不需要在具有未处理异常的程序中符合此算法.特别是,允许CLR通过黑魔法确定没有异常处理程序,并且永远不会运行任何finally块.在某些情况下,无论是否选择在CLR的某些版本中这样做,我都不知道.在任何情况下,您都不能依赖该行为来确定程序的正确性,因为具有未处理异常的程序不正确.
该规范还指出,CLR可以随心所欲地选择是否启动调试器.CLR不需要在调试或发布中执行相同的操作,并且不需要在版本之间执行相同的操作.
这里的问题是你根据过去的经验形成了一个期望,但没有文件说过去的经验是预测未来的基础.相反,恰恰相反; 允许CLR在具有未处理异常的程序中根据月亮的相位改变其行为.
如果您希望程序的行为可预测,则不要抛出未处理的异常.
所以,如果我理解正确,只要在上游某处有另一个捕获,finally块就会执行?
不,我没有这么说.让我们分解吧.
如果程序中存在未捕获的异常,则程序的行为是实现定义的.无论你得到什么样的行为,这都是你得到的行为,而CLR是在产生这种行为的权利范围内.这包括运行finally块和不运行finally块.
假设没有未捕获的异常,并抛出异常,并且在捕获的过程中有一个finally块.是否保证finally块将执行? 不.有许多事情可以阻止最终阻止在法律程序中执行.例如,沿途的另一个最终块或异常过滤器可能会进入无限循环或快速失败,其中任何一个都会阻止finally块执行.如果您绝对必须运行一些清理代码,那么您需要研究约束执行区域.(我不知道它们是如何工作的;我从来没有必要学习.我听说它们很棘手.)
保证的是,如果控制离开最终受保护的块,则最终代码将运行.在异常过滤器期间运行的代码不计入离开块,并且快速失败不会导致程序控制退出块,这会导致程序控制突然结束.显然,无限循环会导致控制从不退出块.
我想在一个真正未处理的异常的情况下,程序应该终止,所以孤立的数据库连接/事务应该不是问题?
不管是不是问题,我都不能说.询问您的数据库的作者.
该程序很可能会终止,但我再次注意到CLR不需要具有该行为.例如,假设有一些线程在CLR试图判断您是否安装了调试器时继续运行.CLR在权利范围内可以任意长时间地计算出来,因此在保持该线程运行的权利范围内.无论是否,我不知道.我所知道的是,我不想依赖任何一种行为.
另外,使用'AppDomain.CurrentDomain.UnhandledException事件计数作为'处理'
不.如果那个东西运行然后有一个未处理的异常,程序的行为是实现定义的.该事件处理程序应仅用于执行记录程序存在错误的事实.
在 Framework 4.0 之前,未处理的异常启动了“Microsoft .NET 错误报告垫片”,它显示提供“调试”或“关闭程序”的对话框。该填充程序允许 .NET 应用程序“干净地”关闭。
从 Framework 4.0 开始(据我所知),未处理的异常会导致 Windows 启动 Windows 错误报告 (WER),该报告在任务管理器中显示为 Windows 问题报告。此应用程序显示与填充程序类似的对话框,但采用更强硬的方法来终止应用程序,可能调用 TerminateProcess 或 TerminateThread,这将不允许在行为不当的进程中执行任何进一步的代码。
| 归档时间: |
|
| 查看次数: |
708 次 |
| 最近记录: |