我有一个简单的try-catch-finally代码块,它在.NET3.5中按预期工作,但是相同的代码在用.NET4.5.1创建的项目上的行为完全不同。基本上,在.NET4.5.1中,如果发生异常,"finally“块就不会命中,这不是我在try-catch-finally块中所期望的行为。我在不同的机器上试了试,我的另外两个同事也试了试,我们都得到了相同的结果。这对我来说是个问题,因为我使用finally块来关闭DataReaders、某些连接等等。
如果在没有调试器的RELEASE模式下或在运行RELEASE编译的EXE文件时抛出异常,则不会命中"finally“块。在调试模式下,两个.NET版本都命中了"finally“块。
同样,下面的代码在没有调试器的.NET3.5发布模式下的行为与预期一样,但在.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!");
}
}发布于 2015-06-17 14:40:50
下面的代码在没有调试器的.NET3.5发布模式下按预期运行,但在.NET4.5.1中不能。我是不是遗漏了什么?
注意:我夸大了这种行为的不确定程度;感谢评论者Voo指出这一点。我一开始就应该回到规范上来。
是。CLI规范要求CLR在出现未处理的异常时结束程序。只有在异常得到处理的情况下,才需要运行finally块。规范对于CLR在存在未处理的异常时是否需要、允许或禁止执行finally块的问题含糊其辞;安全的假设是,这是规范未定义的行为,这取决于特定的实现。
CLR可以随意选择是否为未处理的异常运行finally块。许多人认为CLR使用这种算法:在出现异常时,遍历调用堆栈,在执行过程中执行finally块,查找处理程序;如果没有找到处理程序,则终止进程。在具有未处理异常的程序中,CLR不需要符合此算法。特别是,允许CLR通过黑魔法确定没有异常处理程序,并且永远不会运行任何finally块。在某些情况下,在某些版本的CLR中,它是否选择这样做,我不知道。在任何情况下,您都不能依赖该行为来确保程序正确性,因为具有未处理异常的程序是不正确的。
该规范还指出,CLR可以根据自己的喜好选择是否启动调试器。CLR在调试或发布时不需要执行相同的操作,并且在不同版本之间也不需要执行相同的操作。
这里的问题是,你基于过去的经验形成了一个期望,但没有文档表明过去的经验是预测未来的基础。相反,恰恰相反;CLR被允许根据月相来改变它的行为,如果它喜欢的话,在一个有一个未处理异常的程序中。
如果你希望你的程序的行为是可预测的,那么不要抛出未处理的异常。
所以如果我没理解错的话,只要上游的某个地方有另一个catch,
块就会执行?
不,我没这么说。让我们把它分解一下。
如果程序中存在未捕获的异常,则程序的行为是由实现定义的。无论你得到什么行为,那就是你得到的行为,CLR有权产生这种行为。这包括运行finally块和不运行finally块。
假设没有未捕获的异常,并且抛出了一个异常,并且在捕获的过程中有一个finally块。是否保证执行finally块?No。有许多事情可以阻止最终块在合法程序中执行。例如,另一个finally块或异常筛选器可能会进入无限循环或快速失败,这两种情况中的任何一种都会阻止finally块执行。如果你一定要运行一些清理代码,那么你需要研究受约束的执行区域。(我不知道它们是如何工作的;我从来没有必要学习。我听说他们很棘手。)。
可以保证的是,如果控制离开了最终受保护的块,那么最终的代码将会运行。在异常筛选器期间运行的代码不算作离开块,并且快速失败不会导致程序控制退出块,它会导致程序控制突然结束。显然,无限循环会导致控件永远不会退出某个块。
我认为在一个真正未处理的异常的情况下,程序无论如何都应该终止,所以孤立的数据库连接/事务应该不是问题?
不管这是不是一个问题,我不能说。请询问您的数据库的作者。
程序很可能会终止,尽管我再次注意到CLR不需要具有该行为。例如,假设有一些线程在CLR尝试确定您是否安装了调试器时继续运行。CLR有权花任意长的时间来弄清楚这一点,因此也有权保持线程运行。不管是不是这样,我都不知道。我所知道的是,我不想依赖任何一种行为。
另外,使用'AppDomain.CurrentDomain.UnhandledException
‘是否将事件计数为'handling’
不是的。如果该程序运行,则会出现未处理的异常,并且程序的行为是由实现定义的。该事件处理程序应该仅用于记录程序有bug的事实。
发布于 2015-06-17 16:09:11
在理柏所写的内容之上,请注意它是用MSDN编写的……在try...finally下
但是,如果异常未处理,则finally块的执行取决于异常展开操作的触发方式。而这又取决于您的计算机的设置方式。
和
通常,当未处理的异常结束应用程序时,是否运行finally块并不重要。
然后它继续解释说,如果你把一个try... catch放在一个“高”的级别,那么内部的try... finally就会被执行。
发布于 2015-06-17 08:01:34
在Framework4.0之前,未处理的异常启动了“微软.NET错误报告填充”,它显示了提供给“调试”或“关闭程序”的对话框。填充程序允许.NET应用程序“干净地”关闭。
从Framework4.0(据我所知)开始,未处理的异常导致Windows启动Windows错误报告(WER),在任务管理器中显示为Windows问题报告。这个应用程序显示了一个类似于填充程序的对话框,但采用了一种更强硬的方法来终止应用程序,可能会调用TerminateProcess或TerminateThread,这将不允许在行为异常的进程中执行任何进一步的代码。
https://stackoverflow.com/questions/30879554
复制相似问题