Legacy error handling routines to .NET
By-default, VB6 to VB.NET conversions keep On Error statements the same to achieve a higher functional equivalence and a smoother migration process. However, the VBUC can be configured to generate try-catch structured error-handling statements. In the case of C#, the conversion to try-catch is mandatory.
Some very complex spaghetti-code patterns might not be recognized by the VBUC, but it already supports a large amount of cases with different combinations of statements (On Error Goto, Labels, Goto, Resume, Exit Sub/Function, Break, etc.)
Some straightforward examples are shown below.
Example 1 (simple case with block finalizer):
[VB6]
On Error Goto errLabel
<CodeBlock1>
<Exit Sub/Function>
errlabel:
<CodeBlock2>
[C#.NET]
try
{
<CodeBlock1>
<Return>
}
catch
{
<CodeBlock2>
}
Example 2 (simple case with no block finalizer):
[VB6]
On Error Goto errLabel
<CodeBlock1>
<Exit Sub/Function>
errlabel:
<CodeBlock2>
[C#.NET]
try
{
<CodeBlock1>
<Return>
}
catch
{
<CodeBlock2>
}
Example 3 (common case with resume statement):
[VB6]
On Error Goto errLabel
<CodeBlock1>
resumeLabel:
<CodeBlock2>
<Exit Sub/Function>
errlabel:
<CodeBlock3>
Resume resumeLabel
[C#.NET]
try
{
<CodeBlock1>
<Return>
}
catch
{
<CodeBlock3>
}
finally
{
<CodeBlock2>
}
In .NET the equivalent structured model for On Error Resume Next would be a Try-Catch for every single statement in the block where the “resume next” is active. Applying that kind of conversion would result in very low quality code. Instead, it is recommended that the error-prone statements be manually identified and handled individually with a different model. However, the VBUC recognizes some cases where there is only one statement that can throw an exception, and converts the On Error Resume Next with a Try-Catch for that statement.
[VB6]
Public Function FileExists(ByVal strFile As String) As Integer
Dim lSize As Long
On Error Resume Next
'* set lSize to -1
lSize = -1
'Get the length of the file
lSize = FileLen(strFile)
If lSize = 0 Then
'* File is zero bytes and exists
FileExists = 0
ElseIf lSize > 0 Then
'* File Exists
FileExists = 1
Else
'* Does not exist
FileExists = -1
End If
End Function
Resulting C# Code
The Visual Basic Upgrade Companion’s resulting source code will contain a EWI to indicate the need to perform a manual change over the generated code to obtain functional equivalence. The original method returns a 0 if the file exists with 0 bytes size, a 1 if the file exists and its contents are larger than 0 and -1 if the file doesn’t exist.
static public int FileExists( string strFile)
{
//UPGRADE_TODO: (1069) Error handling statement (On Error Resume Next) was converted to a complex pattern which might not be equivalent to the original. More Information: http://www.vbtonet.com/ewis/ewi1069.aspx
try
{
//* set lSize to -1
int lSize = -1;
//Get the length of the file
lSize = (int) (new FileInfo(strFile)).Length;
if (lSize == 0)
{
//* File is zero bytes and exists
return 0;
} else if (lSize > 0) {
//* File Exists
return 1;
} else
{
//* Does not exist
return -1;
}
}
catch (Exception exc)
{
throw new Exception("Migration Exception: The following exception could be handled in a different way after the conversion: " + exc.Message);
}
return 0;
}
The manual change need to take this example to functional equivalence is to take the “else” code block (return -1;) and place it into the catch handling block.
When converting unstructured error handling to structured try-catch statements, some patterns are applied to remove obsolete uses of Err object inside the error handling block.
The Err members Raise, Number, Source, and Description are considered and converted to equivalent patterns of the caught exception. Other cases where these members cannot be converted to uses of the exception are marked with a warning comment.