当异常是从finallys抛出catch块不被评估 [英] Catch block is not being evaluated when exceptions are thrown from finallys

查看:255
本文介绍了当异常是从finallys抛出catch块不被评估的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这问题就来了,因为试/ finallys,部分有关,因为在.NET 4.0中的工作previously code失败,在.NET 4.5未处理的异常。如果你想详细信息,了解更多的<一个href="https://connect.microsoft.com/VisualStudio/feedback/details/759833/cryptostream-behaves-differently-in-net-4-5-breaks-existing-net-4-0-$c$c"相对=nofollow>微软连接。我用它作为基地为这个例子,所以它可能是有益的参考。

This question came about because code that worked previously in .NET 4.0 failed with an unhandled exception in .NET 4.5, partly because of try/finallys. If you want details, read more at Microsoft connect. I used it as the base for this example, so it might be helpful to reference.

有关谁选择不了解这背后的问题细节的人来说,这里是一个非常快看看那里发生这种情况的条件:

For the people who chose to not read about the details behind this question, here is a very quick look at the conditions where this happened:

using(var ms = new MemoryStream(encryptedData))
using(var cryptoStream = new CryptoStream(encryptedData, decryptor, CryptoStreamMode.Read))
using(var sr = new StreamReader(cryptoStream))

这问题是,有来自CryptoStream的(因为他们是用语句中,这些异常发生在从两个不同的finally块抛出的处置方法抛出的异常)。当 cryptoStream.Dispose()被称为由的StreamReader CryptographicException 被抛出。第二次 cryptoStream.Dispose()被调用时,它使用语句,它抛出一个 ArgumentNullException

This issue is that there are exceptions thrown from the Dispose method of CryptoStream (since they are inside a using statement, these exceptions happen to be thrown from two different finally blocks). When cryptoStream.Dispose() is called by the StreamReader, the CryptographicException is thrown. The second time cryptoStream.Dispose() is called, in its using statement, it throws a ArgumentNullException

下面code除去大部分从上面提供的链接不必要code,而使用语句开卷进入试/ finallys清楚地表明,他们正在投finally块。

The following code removes most of the unnecessary code from the link provided above, and unwinds the using statements into try/finallys to clearly show that they are being throw in finally blocks.

using System;
using System.Security.Cryptography;
namespace Sandbox
{
    public class Program
    {
        public static void Main(string[] args)
        {
            try
            {
                try
                {
                    try
                    {
                        Console.WriteLine("Propagate, my children");
                    }
                    finally
                    {
                        // F1
                        Console.WriteLine("Throwing CryptographicExecption");
                        throw new CryptographicException();
                    }
                }
                finally
                {
                    // F2
                    Console.WriteLine("Throwing ArgumentException");
                    throw new ArgumentException();
                }
            }
            catch (ArgumentException)
            {
                // C1
                Console.WriteLine("Caught ArgumentException");
            }
            // Same behavior if this was in an enclosing try/catch
            catch (CryptographicException)
            {
                // C2
                Console.WriteLine("Caught CryptographicException");
            }

            Console.WriteLine("Made it out of the exception minefield");
        }
    }}

注:尝试/终于对应于使用从引用的code语句扩展

Note: The try/finally correspond to expanded using statements from the referenced code.

输出:


    Propagate, my children
    Throwing CryptographicExecption
    Throwing ArgumentException
    Caught ArgumentException
    Press any key to continue . . .

它不会出现在曾经执行 CryptographicException catch块。然而,去除catch块会导致异常终止运行系统。

It doesn't appear that the CryptographicException catch block is ever executed. However, removing that catch block causes the exception to terminate the runtime.

编辑:这是更新到规范的最新版本。一个我碰巧抓住过MSDN中有旧的措辞。 丢失已经更新到终止

This was updated to the newest revision of the specification. The one I happened to grab off of MSDN had older wording. Lost has been updated to terminated.

潜水到C#规范,部分8.9.5和8.10讨论异常行为:

Diving into the C# spec, sections 8.9.5 and 8.10 discuss exception behavior:

  • 当一个异常被抛出,其中包括一个finally块内,控制转移到第一个catch子句在一个封闭的try语句。这延续了尝试语句,直到一个合适的被发现。
  • 如果一个异常在执行finally块期间抛出,而一个异常已经被传播,该异常终止

终止使得它似乎是一个异常将永远被隐藏在第二抛出的异常,但它似乎并没有成为正在发生的事情。

"Terminated" makes it seem that the first exception would forever be hidden by the second thrown exception, though it doesn't seem to be what is happening.

在大多数情况下,人们很容易想象一下运行时在做什么。在code执行到第一个finally块( F1 )其中的异常。由于异常传播,第二个例外,从第二抛出finally块( F2 )。

For the most part, it's easy to visualize what the runtime is doing. The code executes to the first finally block (F1) where an exception is thrown. As the exception propagates, the second exception is thrown from the second finally block (F2).

根据规范,在 CryptographicException F1 抛出,现在被终止,并且运行时寻找处理程序的ArgumentException 。运行时发现一个处理程序,并执行code为catch块中的的ArgumentException C1 )。

According to the spec, the CryptographicException thrown from F1 is now terminated, and the runtime is looking for a handler for the ArgumentException. The runtime finds a handler, and executes the code in the catch block for the ArgumentException (C1).

下面是它得到雾:规范说,第一个异常将被终止。但是,如果第二个catch块( C2 )从code删除, CryptographicException 这是假想失去了,现在是一个未处理的异常终止的程序。随着 C2 present,在code不会从一个未处理的异常终止,所以在表面上的出现的处理例外,但实际的异常处理code块中永远不会执行。

Here is where it gets foggy: the spec says that the first exception would be terminated. However, if the second catch block (C2) is removed from the code, the CryptographicException that was supposedly lost, is now an unhandled exception that terminates the program. With the C2 present, the code will not terminate from an unhandled exception, so on the surface it appears to be handling the exception, but the actually exception handling code in the block is never executed.

的问题基本上是相同的,但重新措辞的特异性。

The questions are basically the same, but re-worded for specificity.

  1. 它是如何的 CryptographicException 变得由于的ArgumentException 例外从封闭抛出最后终止块,去掉了赶上(CryptographicException)块会导致异常走未处理并终止运行时?

  1. How is it that the CryptographicException becomes terminated due to the ArgumentException exception thrown from the enclosing finally block, as removing the catch (CryptographicException) block causes the exception to go unhandled and terminate the runtime?

由于运行时好像是处理 CryptographicException 赶上(CryptographicException)块是present,为什么不执行块内的code?

Since the runtime seems to be handling the CryptographicException when the catch (CryptographicException) block is present, why is the code inside of the block not executing?

我还在寻找到这样做的实际行为,很多问题的答案已经至少在回答上述问题的部分特别有帮助。


Extra informational Edit

I'm still looking into the actual behavior of this, and many of the answers have been particularly helpful in at least answering parts of the above questions.

另一个奇怪的现象,这种情况发生在运行code与赶上(CryptographicException)块注释掉,是与.NET 4.5和.NET的区别3.5。 .NET 4.5会抛出 CryptographicException 和终止应用程序。 .NET 3.5,但是,似乎根据C#规范的行为更多的地方例外。

Another curious behavior, that happens when you run the code with the catch (CryptographicException) block commented out, is the difference between .NET 4.5 and .NET 3.5. .NET 4.5 will throw the CryptographicException and terminate the application. .NET 3.5, however, seems to behave more according to the C# spec where the exception.


Propagate, my children
Throwing CryptographicExecption

Unhandled Exception: System.Security.Cryptography.CryptographicException [...]
ram.cs:line 23
Throwing ArgumentException
Caught ArgumentException
Made it out of the exception minefield

在.NET 3.5中,我明白我读了规范。唯一的例外变为丢失,或者终止,因为这永远需要被抓住的唯一的事情就是的ArgumentException 。正因为如此,程序可以继续执行。我只有.NET 4.5我的机器上,我不知道如果这种情况发生在.NET 4.0中?

In .NET 3.5, I see what I read in the spec. The exception becomes "lost", or "terminated", since the only thing that ever needs to get caught is the ArgumentException. Because of that the program can continue execution. I only have .NET 4.5 on my machine, I wonder if this happens in .NET 4.0?

推荐答案

事实证明,我的没有的疯狂。根据我得到这个问题的答案,我觉得它好像我有很难理解什么是如此清晰地在规范中列出。这真的不是在所有的难以把握。

As it turns out, I am not crazy. Based on the answers I got to this question, I think it seemed like I was having difficulty understanding what is so clearly outlined in the spec. It's really not at all difficult to grasp.

事实是,该规范是有道理的,而行为不是。当您运行code在一个旧的运行时,它的表现普遍认为这是更是如此完全不同......或至少的出现的到。

The truth is that the spec makes sense, while the behavior wasn't. This is seen even more so when you run the code in an older runtime, where it behaves completely different...or at least appears to.

我所看到的,在我的Win7 x64的机器:

What I saw, on my x64 Win7 machine:

  • .NET v2.0-3.5 - 当 CryptographicException 被抛出WER对话框。按关闭程序后,程序将继续,仿佛execption从未抛出。该应用程序的没有终止。这是人们所期望从阅读规范的行为,并广受建筑师的谁执行的异常处理在.NET中定义的。

  • .NET v2.0-3.5 - WER dialog when the CryptographicException is thrown. After hitting Close the program, the program continues, as if the execption were never thrown. The application is not terminated. This is the behavior one would expect from reading the spec, and is well defined by the architects who implemented exception handling in .NET.

.NET v4.0-4.5 - 不显示任何WER对话框。相反,出现一个窗口询问您是否要调试程序。点击没有导致程序立即终止。没有finally块之后执行。

.NET v4.0-4.5 - No WER dialog is displayed. Instead, a window appears asking if you want to debug the program. Clicking no causes the program to terminate immediately. No finally blocks are executed after that.

事实证明,pretty的很多人谁尝试回答我的问题会得到同样的结果和我一样,这样解释了为什么没人能回答我的问题,为什么运行时间是从异常终止该它吞噬。

As it turns out, pretty much anybody who would try to answer my question would get the exact same results as I did, so that explains why nobody could answer my question of why the runtime was terminating from an exception that it swallowed.

谁会怀疑刚刚在实时调试

您可能已经注意到,在.NET 2运行的应用程序产生比.NET 4不同的错误对话框但是,如果你像我一样,你已经开始期待在开发周期中的窗口,所以你没想到的任何事情。

You may have noticed that running the application under .NET 2 produces a different error dialog than .NET 4. However, if you're like me, you've come to expect that window during the development cycle, and so you didn't think anything of it.

该vsjitdebugger可执行文件被强行终止应用程序,而不是让它继续下去。在2.0运行时, dw20.exe 没有这种行为,其实你看到的第一件事是,WER消息。

The vsjitdebugger executable was forcibly terminating the application, instead of letting it continue. In the 2.0 runtime, dw20.exe doesn't have this behavior, in fact, the first thing you see is that WER message.

由于采用了JIT调试器终止应用程序,它使人们的似乎好像是不符合什么规范说的时候,其实,它的作用。

Thanks to the jit debugger terminating the application, it made it seem like it wasn't conforming to what spec says when, in fact, it does.

要测试这一点,我禁用了vsjitdebugger发动失败时,通过更改注册表键, HKEY_LOCAL_MACHINE \ SOFTWARE \微软\的Windows NT \ CURRENTVERSION \的AeDebug \自动从1比0。果然,应用程序忽略了异常并继续,就像.NET 2.0。

To test this, I disabled the vsjitdebugger from launching on failure, by changing the registry key at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug\Auto from 1 to 0. Sure enough, the application ignored the exception and continued on, just like .NET 2.0.

事实证明,有一种变通方法,但真的没有理由要解决此问题,因为您的应用程序将终止。

As it turns out, there is a workaround, though there's really no reason to workaround this behavior, since your application is terminating.

  1. 当刚刚在实时调试窗口弹出,检查手动选择调试引擎并单击是,您要调试。
  2. 在当前的Visual Studio为您提供了引擎选项,单击取消。
  3. 这将导致程序继续运行,或WER对话框弹出,这取决于你的机器配置。如果出现这种情况,告诉它关闭程序实际上不会关闭它,它会继续运行,如果一切正常。
  1. When the Just-In-Time debugger window pops up, check Manually choose the debugging engines and click yes, that you want to debug.
  2. When Visual Studio gives you engine options, click cancel.
  3. This will cause the program to continue, or a WER dialog to pop up, depending on your machine configuration. If that happens, telling it to close the program won't actually close it, it will continue running as if everything was okay.

这篇关于当异常是从finallys抛出catch块不被评估的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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