抛出try / finally块的双重异常

时间:2012-09-28 14:19:26

标签: vb.net exception try-finally

以下是代码示例:

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

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

我认为FirstException将在SecondException的InnerException属性中,但它似乎不是。

我没有阻止任何事情,因为我真的不需要出现FirstException,我只是对这种行为很感兴趣。

  • 有没有办法知道SecondException在第一次被抛出时 在上层抓住这一切?

  • 如果第一个异常真的被第二个异常覆盖,那么它是什么 原因?

  • 是否会以其他语言发生?这是合乎逻辑的吗?

2 个答案:

答案 0 :(得分:2)

我猜这个问题的主要解释是,你永远不会抓住你的第一个例外并将其传递给链。如果您遇到类似上述情况,您可能会在返回原始调用者的路上抛出几个异常,那么您必须在抛出它们时捕获它们(并在创建下一个时将它们包含为内部异常):< / p>

Dim ex1 As Exception = Nothing
Try
    Throw New Exception("first exception")
Catch ex As Exception
    ex1 = ex
Finally
    Throw New Exception("second exception", ex1)
End Try

或者,可能更好 - 只要在你弄清楚所有例外情况之后再扔掉:

Dim ex1 As Exception = Nothing
Try
    ex1 = New Exception("first exception")
Finally
    Throw New Exception("second exception", ex1)
End Try

抛出和捕捉异常是很昂贵的,所以最好不要扔掉,直到你准备好返回并且只是记录下去。

答案 1 :(得分:1)

.net中异常处理的一个限制是,Finally块中的代码没有很好的方法可以知道什么异常(如果有的话)导致Try块中的代码退出,也没有任何正常的方法可以使finally块中的代码具有这样的信息,使其可用于可能引发异常的代码。

在vb.net中,即使看起来有点难看,也可以以一种非常好的方式来处理事物。

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块的不同组合中出现异常。

如图所示,如果在清理期间发生异常,则该异常将返回给调用者,原始异常是其Data字典中的项。另一种模式是捕获清理时发生的异常并将其包含在原始异常的数据中(这将是未被捕获的)。我的一般倾向是,在许多情况下传播清理期间发生的异常可能更好,因为任何计划处理原始异常的代码都可能期望清理成功;如果无法满足这样的期望,那么逃避的例外应该不是调用者所期望的那样。还要注意,后一种方法需要稍微不同的方法来向原始异常添加信息,因为嵌套Try块中抛出的异常可能需要保存有关嵌套{{{{1}中抛出的多个异常的信息。 1}}阻止。