双重异常抛出try/finally块 [英] Double exception throwing in a try / finally block

查看:153
本文介绍了双重异常抛出try/finally块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是代码示例:

Try
    Throw New FirstException()
Finally
    Throw New SecondException()
End Try

我发现它只会抛出SecondException,而FirstException就会消失.

I figured out it only throws SecondException out and FirstException just vanishes.

我以为FirstException将在SecondException的InnerException属性内,但事实并非如此.

I thought FirstException would be inside InnerException property of SecondException but it appears it is not.

我并没有受到任何阻碍,因为我真的不需要FirstException来显示它,我对此行为很感兴趣.

I'm not blocked on anything as I don't really need the FirstException to show up, I'm just rather intrigued about this behaviour.

  • 有没有办法知道SecondException的确在何时抛出了 在更高级别上捕获全部内容?

  • Is there a way to know SecondException did get thrown first when catching it all at upper level ?

如果第一个异常确实被第二个异常覆盖,那么什么是 原因?

If the first exception really is overriden by the second, what is the reason ?

它是否以其他所有语言出现?这合乎逻辑吗?

Does it happen in every other language ? Is it logical ?

推荐答案

.net中异常处理的局限性之一是,Finally块中的代码没有很好的方法知道什么异常(如果有),导致Try块中的代码退出,finally块中的代码也没有任何正常的方式,因为该信息确实具有可将其提供给可能引发异常的代码的可用信息.

One of the limitations of exception handling in .net is that there is no nice way for code in a Finally block to know what exception, if any, caused the code in the Try block to exit, nor is there any normal way for code in a finally block which does have such information to make it available to code which might throw an exception.

在vb.net中,即使看起来有些丑陋,也可以用一种效果很好的方式来拖拉东西.

In vb.net, it's possible to kludge things in a manner that works pretty well, even though it looks a bit ugly.

Module ExceptionDemo
    Function CopySecondArgToFirstAndReturnFalse(Of T)(ByRef dest As T, src As T) As Boolean
        dest = src
        Return False
    End Function
    Function AnnotateExceptionAndReturnFalse(ex As Exception, TryBlockException As Exception) As Boolean
        If ex Is Nothing Then Return False ' Should never occur
        If TryBlockException Is Nothing Then Return False ' No annotation is required
        ex.Data("TryBlockException") = TryBlockException
        Return False
    End Function

    Sub ExceptionTest(MainAction As Action, CleanupAction As Action)
        Dim TryBlockException As Exception = Nothing
        Try
            MainAction()
        Catch ex As Exception When CopySecondArgToFirstAndReturnFalse(TryBlockException, ex)
            ' This block never executes, but above grabs a ref to any exception that occurs
        Finally
            Try
                CleanupAction()
            Catch ex As Exception When AnnotateExceptionAndReturnFalse(ex, TryBlockException)
                ' This block never executes, but above performs necessary annotations
            End Try
        End Try
    End Sub

    Sub ExceptionTest2(Message As String, MainAction As Action, CleanupAction As Action)
        Debug.Print("Exception test: {0}", Message)
        Try
            ExceptionTest(MainAction, CleanupAction)
        Catch ex As Exception
            Dim TryBlockException As Exception = Nothing
            Debug.Print("Exception occurred:{0}", ex.ToString)
            If ex.Data.Contains("TryBlockException") Then TryBlockException = TryCast(ex.Data("TryBlockException"), Exception)
            If TryBlockException IsNot Nothing Then Debug.Print("TryBlockException was:{0}", TryBlockException.ToString)
        End Try
        Debug.Print("End test: {0}", Message)
    End Sub
    Sub ExceptionDemo()
        Dim SuccessfulAction As Action = Sub()
                                             Debug.Print("Successful action")
                                         End Sub
        Dim SuccessfulCleanup As Action = Sub()
                                              Debug.Print("Cleanup is successful")
                                          End Sub
        Dim ThrowingAction As Action = Sub()
                                           Debug.Print("Throwing in action")
                                           Throw New InvalidOperationException("Can't make two plus two equal seven")
                                       End Sub
        Dim ThrowingCleanup As Action = Sub()
                                            Debug.Print("Throwing in cleanup")
                                            Throw New ArgumentException("That's not an argument--that's just contradiction")
                                        End Sub
        ExceptionTest2("Non-exception case", SuccessfulAction, SuccessfulCleanup)
        ExceptionTest2("Exception in main; none in cleanup", ThrowingAction, SuccessfulCleanup)
        ExceptionTest2("Exception in cleanup only", SuccessfulAction, ThrowingCleanup)
        ExceptionTest2("Exception in main and cleanup", ThrowingAction, ThrowingCleanup)
    End Sub
End Module

上面的模块以几个帮助器模块开始,它们应该在它们自己的异常帮助器"模块中. ExceptionTest方法显示可能在TryFinally块中都引发异常的代码模式. ExceptionTest2方法调用ExceptionTest并报告异常(如果有异常). ExceptionDemo调用ExceptionTest2的方式会导致TryFinally块的不同组合引起异常.

The module above starts with a couple helper modules which should probably be in their own "Exception helpers" module. The ExceptionTest method shows the pattern for code which might throw an exception in both the Try and Finally block. The ExceptionTest2 method calls ExceptionTest and reports what exception if any comes back from it. ExceptionDemo calls ExceptionTest2 in such a way as to cause exceptions in different combinations of the Try and Finally blocks.

如图所示,如果清理期间发生异常,则该异常将返回给调用方,原始异常是其Data词典中的一项.另一种模式是捕获在清除过程中发生的异常,并将其包含在原始异常的数据中(将保留未捕获的异常).我的一般倾向是,在许多情况下,传播在清除过程中发生的异常可能更好,因为任何计划处理原始异常的代码都可能期望清除成功;如果不能满足这样的期望,则转义的例外可能不应该是呼叫者所期望的.还要注意,后一种方法需要向原始异常中添加信息的方法稍有不同,因为在嵌套Try块中引发的异常可能需要保存有关在嵌套Finally块中引发的多个异常的信息

As shown, if an exception occurs during cleanup, that exception will be returned to the caller, with the original exception being an item in its Data dictionary. An alternative pattern would be to catch the exception that occurs on cleanup and include it in the data of the original exception (which would be left uncaught). My general inclination is that it's probably better in many cases to propagate the exception that occurs during cleanup, since any code which was planning to deal with the original exception will probably expect that cleanup succeeded; if such an expectation cannot be met, the exception that escapes should probably not be the one the caller was expecting. Note also that the latter approach would require a slightly different method of adding information to the original exception, since an exception which is thrown in a nested Try block might need to hold information about multiple exceptions that were thrown in nested Finally blocks.

这篇关于双重异常抛出try/finally块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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