尝试-catch-finally块与.NET4.5.1问题 [英] Try-Catch-Finally block problems with .NET4.5.1

查看:206
本文介绍了尝试-catch-finally块与.NET4.5.1问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的try-catch-finally代码块预期.NET3.5的作品,但相同的代码的行为与.NET4.5.1创建的项目完全不同。基本上,.NET4.5.1了最后块没有得到,如果发生异常而不是从我在try-catch-finally块的预期行为的打击。我试着在不同的机器上,并有我的2其他同事也在努力,我们都得到了相同的结果。这对我来说是一个问题,因为我用finally块来关闭的DataReader,某些连接,以及诸如此类的东西。



.NET4.5.1不打终于块如果一个异常被抛出的发布模式没有调试器或运行在发行版编译EXE 文件时。在调试模式下两个版本的.NET打终于块。



再次下面的代码的行为与预期.NET3.5发布模式,不调试,但不是在。 NET4.5.1。我缺少的东西吗?有人可以帮忙吗?



 类节目
{
静态无效的主要(字串[] args)
{

{
字符串= NULL;
变种X =则为a.length;
Console.WriteLine(x)的;
}
赶上(异常前)
{
扔;
}
终于
{
Console.WriteLine(这是finally块。);
}
Console.WriteLine(你不应该在这里如果有异常发生!);
}
}


解决方案

下面的代码的行为与预期在没有调试.NET3.5释放模式,但不是在.NET4.5.1。 ?我失去了一些东西。




请注意:我夸大了这种行为未定义的烦躁的水平;由于评论者VOO指出了这一点。我应该已经回到摆在首位的规范。



是的。该CLR由CLI规范要求以结束该程序时,有未处理的异常。它只的需要的到,如果异常被处理最终运行块。该规范是的CLR是否是必需的,允许的,或不允许当有未处理的异常执行finally块的问题含糊不清;的安全的假设是则说这是受本说明书不确定的行为,这是达到一个特定的实施



的CLR可以选择运行最后块对于未处理的异常,或没有在其心血来潮。许多人认为,CLR使用该算法:根据异常,走到调用堆栈,执行finally块,当您去,寻找处理;如果没有处理程序被发现,终止进程。在CLR不要求符合该算法在程序中有未处理的异常。特别是,CLR允许通过黑魔法,以确定没有异常处理程序,并且永远不会运行任何finally块。无论是选择在某些情况下,CLR的一些版本这样做还是不行,我不知道。在任何情况下,你可以依靠的行为程序的正确性,因为的有未处理的异常的程序是不正确的。



规范还指出,CLR可以选择提供开始调试与否,在它的心血来潮。在CLR不需要做同样的事情在调试或释放,并且它做同样的事情,因版本不是必需的。



这里的问题是,你形成根据以往的经验的期望,但没有文件它说,过去的经验是对未来的预测的基础。相反,正好相反;在CLR允许改变,如果喜欢,在有未处理的异常程序中的月相的基础上,它的行为。



如果你希望你的程序做人预见那么的不扔未处理的异常




所以,如果我理解正确的话,只要有另一个抓上游某处,finally块将执行?




没有,我没这么说。让我们来分析一下。



如果没有在程序未捕获的异常,则程序的行为是实现定义。你不管的行为,这就是你所得到的行为,和CLR是其内部的生产权的行为。这既包括运行finally块,而不是最终运行块。



假设没有一个未捕获的异常,并抛出一个异常,并有一个最后沿途拦截到catch。难道保证finally块将执行? 即可。有可能阻止终于从一个合法的程序执行阻止很多东西。例如,另一个finally块或沿途异常过滤器会进入一个无限循环或快速失败,其中任何一个会阻止终于从执行阻塞。如果你绝对肯定必须有一些清理代码运行,那么你需要研究约束的执行区域。 (我不知道他们是如何工作的,我从来没有需要学习我听说他们有猫腻。)。



什么是保证的是,的如果控制离开一个最终保护块,然后最终代码将运行。在异常过滤器运行的代码不能算作离开块,并且快速失败不会导致程序控制退出块,它会导致程序控制突然结束。显然,无限循环导致控制永远不会退出块。




我在一个真正的未处理的异常的情况下,假设,程序应该终止反正这样一个孤立的数据库连接/事务不应该是一个问题?




无论是一个问题还是不行,我不能说。问问你的数据库的作者。



很可能的,该计划将终止,但我再次指出,CLR不需要有这种行为。假设例如有一些线程上,而CLR正试图找出是否已安装或没有调试器来运行保持。在CLR是在其权利采取任意长明白这一点,因此,其权利范围内保持这种线程运行。不管它与否,我不知道。我所知道的是,我不想依赖任一行为。




此外,没有使用'AppDomain.CurrentDomain.UnhandledException事件算作处理




不。如果那个东西运行再有就是未处理的异常,程序的行为是实现定义。该事件处理程序应该只用来做这样的事情记录,该方案有一个错误的事实。


I have a simple try-catch-finally code block that works as expected in .NET3.5, but the same code behaves completely different on a project created with .NET4.5.1. Basically, in .NET4.5.1 the "finally" block doesn't get hit if an exception occurs which is not the behavior I expected from the try-catch-finally block. I tried in different machines, and had 2 other colleagues of mine also trying and we all got the same result. This is a concern for me, because I use the finally block to close DataReaders, certain connections, and whatnot.

.NET4.5.1 does not hit the "finally" block if an exception is thrown in RELEASE mode without debugger or when running the RELEASE compiled EXE file. In debug mode both .NET versions hit the "finally" block.

Again, the code below behaves as expected in .NET3.5 RELEASE mode without debugger but not in .NET4.5.1. Am I missing something? Can someone help?

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

解决方案

the code below behaves as expected in .NET3.5 RELEASE mode without debugger but not in .NET4.5.1. Am I missing something?

NOTE: I had overstated the level of undefined-ness of this behaviour; thanks to commenter Voo for pointing that out. I should have gone back to the spec in the first place.

Yes. The CLR is required by the CLI specification to end the program when there is an unhandled exception. It is only required to run finally blocks if the exception is handled. The spec is vague on the question of whether the CLR is required, permitted, or disallowed to execute finally blocks when there is an unhandled exception; the safe assumption is then to say that this is behaviour that is undefined by the specification, and that is up to a particular implementation.

The CLR can choose to run finally blocks for unhandled exceptions, or not, at its whim. Many people believe that the CLR uses this algorithm: upon exception, walk up the call stack, executing finally blocks as you go, looking for handlers; if no handler is found, terminate the process. The CLR is not required to conform to this algorithm in a program with an unhandled exception. In particular, the CLR is permitted to determine by black magic that there is no exception handler, and never run any finally blocks. Whether it chooses to do so or not in some versions of the CLR in some circumstances, I don't know. In no case can you rely on that behavior for the correctness of your program because a program that has an unhandled exception is not correct.

The specification also notes that the CLR can choose to offer to start debuggers or not, at its whim. The CLR is not required to do the same thing in debug or release, and it is not required to do the same thing from version to version.

The problem here is that you formed an expectation based on past experience, but there is no documentation which says that past experience is a basis for a prediction of the future. Rather, just the opposite; the CLR is permitted to change its behavior on the basis of the phase of the moon if it likes, in a program that has an unhandled exception.

If you want your program to behave predictably then do not throw unhandled exceptions.

So if I understand you correctly, as long as there is another catch somewhere upstream, the finally block will execute?

No, I didn't say that. Let's break it down.

If there is an uncaught exception in the program then the program's behavior is implementation-defined. Whatever behavior you get, that's the behavior you got, and the CLR is within its rights to produce that behavior. That includes both running finally blocks and not running finally blocks.

Suppose there is not an uncaught exception, and an exception is thrown, and there is a finally block along the way to the catch. Is it guaranteed that the finally block will execute? No. There are many things that could prevent that finally block from executing in a legal program. For example, another finally block or exception filter along the way could go into an infinite loop or fast fail, either of which would prevent the finally block from executing. If you ABSOLUTELY POSITIVELY must have some cleanup code run then you need to be researching Constrained Execution Regions. (I don't know how they work; I've never had need to learn. I hear they are tricky.).

What is guaranteed is that if control leaves a finally-protected block then the finally code will run. Code run during exception filters does not count as leaving the block, and failing fast does not cause program control to exit a block, it causes program control to end abruptly. Obviously infinite loops cause control to never exit a block.

I suppose in the case of a truly unhandled exception, the program should terminate anyways so an orphaned DB connection/transaction shouldn't be an issue?

Whether it is an issue or not, I cannot say. Ask the author of your database.

It is very likely that the program will terminate, though again I note that the CLR is not required to have that behavior. Suppose for example there is some thread that keeps on running while the CLR is trying to figure out whether you have a debugger installed or not. The CLR is within its rights to take arbitrarily long to figure that out, and therefore within its rights to keep that thread running. Whether it does or not, I don't know. What I do know is that I would not want to rely on either behavior.

Also, does using the 'AppDomain.CurrentDomain.UnhandledException event count as 'handling'

Nope. If that thing runs then there was an unhandled exception, and the behavior of the program is implementation-defined. That event handler should be used only to do things like log the fact that the program has a bug.

这篇关于尝试-catch-finally块与.NET4.5.1问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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