only for RuBoard |
Sometimes it is necessary to rerun code that has triggered an error. Unfortunately, there is no good way to rerun code by using structured exception handling. Example 6-9 shows one method that uses nested Try blocks, which is ideal if you need to retry code only a few times.
Public Shared Sub Main( ) Try RetryMethod( ) Catch e As Exception Try RetryMethod( ) Catch e As Exception 'Fail End Try End Try End Sub
Nested Try blocks are great unless you want to retry your code more than a few times. Beyond that, reading the code becomes more difficult. If someone has to scroll the code window out to column 420 to see what you have donewell, they will laugh at you and tell people about it on the elevator.
Try blocks are re-entrant , so you can use a Goto to jump back into a Try block that already executed. Example 6-10 demonstrates this technique.
Imports System Public Class App Public Shared Sub Main( ) Dim attempts As Integer = 0 Dim maxRetries As Integer = 5 Try 'Code to be retried n times retry: attempts += 1 Console.WriteLine("Attempt {0}", attempts.ToString( )) 'Simulate error - jumps to Catch block Throw New Exception( ) Catch e As Exception If attempts = maxRetries Then GoTo done End If GoTo retry done: End Try End Sub End Class
This code does not flow well, and it is difficult to read. It exists just in case someone out there decides to be clever. Stop trying to be clever when you code. There is a better way to retry a path of execution; you can use recursion from a Catch block and monitor how many attempts were made on the method with a private instance variable, which is shown in Example 6-11.
The Goto Is ObsoleteDon't believe the hype. Before structured error handling, the Goto did have a place in structured code. When several resources, such as database connections and file handles, were allocated, the Goto allowed a single "cleanup" location. Consider the following pseudocode: Public Sub PseudoCode( ) Dim conn As New OleDbConnection(...) Dim fStream As FileStream = File.Open(...) If error Then Goto cleanup End If If error Then Goto cleanup End If If error Then Goto cleanup End If cleanup: conn.Close( ) fstream.Close( ) End Sub This pattern allows cleanup to be performed in a single place rather than being repeated whenever an error occurs. However, this pattern is no longer necessary because with structured exception handling, cleanup code can be placed in a Finally block. |
Imports System Public Class Retry Private attempts As Integer = 0 Private Const maxRetries As Byte = 5 Public Sub Go( ) Try 'Code to retry0 Console.WriteLine("Attempt #{0}", _ attempts.ToString( )) 'Simulate error Throw New Exception( ) Catch e As Exception When attempts < maxRetries attempts += 1 Go( ) 'Call method again Catch e As Exception 'Failed so handle here End Try 'Reset attempt counter attempts = 0 End Sub End Class Public Class App Public Shared Sub Main( ) Dim r As New Retry( ) r.Go( ) Console.ReadLine( ) End Sub End Class
Retrying code multiple times is considerably easier with the conditional handling of exceptions. Remember, exceptions are caught in the order they are received. In Example 6-11, the first exception handler's When clause provides a simple alternative to rerunning a block of code:
Try Go( ) 'Code that you want to re-run on failure Catch e As Exception When attempts < maxRetries attempts += 1 Go( ) 'Call method again Catch e As Exception 'Failed so handle here End Try
After the internal counter exceeds its limit, the condition on the first Catch block is no longer valid, and the second handler catches any exception. The example ignores the exception, but in this situation, you could probably log the error as discussed earlier in the chapter.
|
only for RuBoard |