Code Focused

Life Without On Error Resume Next

The alternative to that simple error-handling combo is the Try...Catch, but it's not as simple as wrapping up your code with it.

Long before .NET arrived on the scene, the On Error statement in Visual Basic formed the foundation of that language's error management options. Through the judicious use of On Error GoTo statements and related error objects, you could craft error-handling code that was every bit as rugged and nearly as structured as the modern Try...Catch alternative. But when you didn't care anymore, there was this:

On Error Resume Next DoSomethingUnsafe() HereIsMoreDanger()

The On Error statement's Resume Next clause told the world, "Do what you want; ask me later if I care." It was a great way to ignore low-risk errors in your source code. But when misused, the statement could greatly complicate debugging and data issues. And, yet, there were times when it was the right tool. The cleanup of low-priority resources just before exiting an application is an example that comes to mind:

On Error Resume Next resourceOne.Cleanup() resourceTwo.Cleanup() resourceThree.Cleanup() End

When migrating such code to its structured alternative, the temptation is to wrap it all up in one large Try statement:

Try resourceOne.Cleanup() resourceTwo.Cleanup() resourceThree.Cleanup() Catch ' ----- Ignore any error. End Try End

Unfortunately, this isn't the correct conversion, because any exception thrown by the cleanup of resourceOne will cause the code to completely skip the two remaining logic lines. A more accurate translation into modern .NET code would provide error handlers for each trouble-prone statement, as shown in Listing 1.

Listing 1: The Correct Way To Use Try…Catch

Try resourceOne.Cleanup() Catch ' ----- Ignore any error. End Try Try resourceTwo.Cleanup() Catch ' ----- Ignore any error. End Try Try resourceThree.Cleanup() Catch ' ----- Ignore any error. End Try End

The code in Listing 1 is correct, and it provides task-specific opportunities to deal with any errors that do occur, even when moving from a procedure that formerly tossed caution to the wind.

Despite the validity of this code, you might wonder how the Visual Basic .NET compiler deals with On Error Resume Next. By building your Visual Basic project, and then extracting out the compiled result using the .NET Framework Intermediate Language (IL) Disassembler tool (ILDASM.EXE), you can see exactly what the compiler does. It's IL, so it's not pretty. But the Visual Basic code presented in Listing 2 shows generally what the compiler attempts to do.

Listing 2: What the Compiler Tries To Do, in Visual Basic

Dim position As Integer Try position = 1 Statement01: position = 2 resourceOne.Cleanup() Statement02: position = 3 resourceTwo.Cleanup() Statement03: position = 4 resourceThree.Cleanup() Statement04: position = 0 GoTo EndOfLogic DealWithIt: Select Case position Case 0: GoTo EndOfLogic Case 1: GoTo Statement01 Case 2: GoTo Statement02 Case 3: GoTo Statement03 Case 4: GoTo Statement04 End Select Catch GoTo DealWithIt End Try EndOfLogic: End

The code depends heavily on the GoTo statement, using it to jump back into the action if an error ever does occur halfway through. It seems like a dramatic increase in code.

I'm not an expert in software benchmarking, but my guess is that the performance overhead inherent in repeatedly entering and exiting error handling blocks exceeds the extra time consumed by assigning the position variable over and over again. And if no exception is ever thrown, the entire DealWithIt block is passed over completely.

Which method should you use when replacing your unstructured error statements? It's difficult to answer without knowing the exact nature of your routine's logic. But if you have a secret desire to read through pages of assembly language-style code, using the output from the Visual Basic compiler isn't a bad place to start.