下面的代码示例:
Try
Throw New FirstException()
Finally
Throw New SecondException()
End Try
我想通了,它只是抛出SecondException并FirstException刚刚消失。
我想FirstException会SecondException的InnerException属性里面,但似乎事实并非如此。
我不会阻止任何东西,因为我并不真正需要的FirstException展现出来,我只是好奇,而有关此问题。
唯一的例外在.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方法显示其可能在这两个抛出异常的代码模式Try
和Finally
块。 该ExceptionTest2方法调用ExceptionTest和报告什么异常,如果任何来自回来。 ExceptionDemo以这样的方式来引起不同的组合异常调用ExceptionTest2 Try
和Finally
的块。
如图所示,如果清理期间发生异常,该异常将被返回给调用者,与原来的例外是在其一个项目Data
字典。 一个替代图案将赶上上清理发生异常并将其包括在原始异常(这将留下未捕获的)的数据。 我总的倾向是,它可能在许多情况下,更好地传播该清理过程中发生异常,因为这是计划来处理原始异常可能会想到的是清除任何成功的代码; 如果这样的期望不能得到满足,逃逸的例外可能不应该是一个呼叫者期待。 还要注意的是,后一种方法需要将信息添加到原始异常的方法稍有不同,因为这是在嵌套抛出的异常Try
块可能需要按住约嵌套被抛出该多个异常信息的Finally
块。
我猜为什么这样工作的主要解释是,你永远不会赶上你的第一种例外情形,并且在传递链。 如果你有一个像上面的一个情况下,你可以在路上扔几个例外回原来的调用者,那么你必须要么赶上他们,因为他们被抛出(并创造下一个时,它们作为内部异常):
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
抛出和捕获异常昂贵,所以它可能是最好不要扔,直到你准备返回,只是沿途记录。