.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
块中抛出的多个异常的信息。
http://stackoverflow.com/questions/1482395/what-happens-if-both-catch-and-finally-blocks-throw-exception –
回答了我的第一个问题,谢谢。我仍然不知道为什么它会以这种方式发生,这是一种常见且众所周知的方式来处理多个投掷,并且没有真正的解释吗? –