This section covers transformations that are applied to enhance certain elements with C# features.
1. Expression-bodied members.
Expression-bodied members refer to a more concise syntax for defining class members, such as properties or methods, using an expression instead of an entire block of code.
1.1. On
When choosing this option, the VBUC will apply a special pattern recognition mechanism to generate expression-bodied members when necessary.
Original VB6 Code
Public Property Get Name() As String
Name = m_name
End Property
Public Property Let Name(newName As String)
m_name = newName
End Property
Public Property Get Age() As String
Age = m_age
End Property
Public Property Let Age(newValue As String)
Dim newValue2 As Integer
newValue2 = CInt(newValue)
If newValue2 > 0 And newValue2 < 12 Then
m_age = "Enfant"
ElseIf newValue2 >= 12 And newValue2 < 18 Then
m_age = "Teenager"
ElseIf newValue2 >= 18 And newValue2 < 60 Then
m_age = "Adult"
Else
m_age = "Elder"
End If
End Property
Public Property Get Nationality() As String
Nationality = "Costa Rican"
End Property
C# Code
private string m_name = "";
private string m_age = "";
public string Name
{
get => m_name;
set => m_name = value;
}
public string Age
{
get => m_age;
set
{
int newValue2 = Convert.ToInt32(Double.Parse(value));
if (newValue2 > 0 && newValue2 < 12)
{
m_age = "Enfant";
}
else if (newValue2 >= 12 && newValue2 < 18)
{
m_age = "Teenager";
}
else if (newValue2 >= 18 && newValue2 < 60)
{
m_age = "Adult";
}
else
{
m_age = "Elder";
}
}
}
public string Nationality => "Costa Rican";
1.2. Off
Choosing this option, the VBUC will generate blocks of code as default.
Original VB6 Code
Public Property Get Name() As String
Name = m_name
End Property
Public Property Let Name(newName As String)
m_name = newName
End Property
Public Property Get Age() As String
Age = m_age
End Property
Public Property Let Age(newValue As String)
Dim newValue2 As Integer
newValue2 = CInt(newValue)
If newValue2 > 0 And newValue2 < 12 Then
m_age = "Enfant"
ElseIf newValue2 >= 12 And newValue2 < 18 Then
m_age = "Teenager"
ElseIf newValue2 >= 18 And newValue2 < 60 Then
m_age = "Adult"
Else
m_age = "Elder"
End If
End Property
Public Property Get Nationality() As String
Nationality = "Costa Rican"
End Property
C# Code
private string m_name = "";
private string m_age = "";
public string Name
{
get
{
return m_name;
}
set
{
m_name = value;
}
}
public string Age
{
get
{
return m_age;
}
set
{
int newValue2 = Convert.ToInt32(Double.Parse(value));
if (newValue2 > 0 && newValue2 < 12)
{
m_age = "Enfant";
}
else if (newValue2 >= 12 && newValue2 < 18)
{
m_age = "Teenager";
}
else if (newValue2 >= 18 && newValue2 < 60)
{
m_age = "Adult";
}
else
{
m_age = "Elder";
}
}
}
public string Nationality
{
get
{
return "Costa Rican";
}
}
2. Generate Auto Implemented Properties
2.1. On
Auto-implemented properties will be generated when the original VB6 properties follow the basic standard pattern.
This feature verifies if there is a property defined on a local private field (both shares the same type) and it removes the field declarations and just leaves an auto-implemented property, replacing any reference to the field with a reference to the property in the class.
This feature is available for C# only.
Original VB6 code:
Private IntVar As Integer
Private BoolVar As Boolean
Private StrVar As String
Public Property Let IntVarProp(value As Integer)
'some comments for IntVarProp property header'
IntVar = value
'some comments for IntVarProp property footer'
End Property
Public Property Get IntVarProp() As Integer
'some comments for IntVarProp property header'
IntVarProp = IntVar
'some comments for IntVarProp property footer'
End Property
Public Property Let BoolVarProp(value As Boolean)
BoolVar = value
End Property
Public Property Get BoolVarProp() As Boolean
BoolVarProp = BoolVar
End Property
Public Property Let StrVarProp(value As String)
StrVar = value
End Property
Public Property Get StrVarProp() As String
StrVarProp = StrVar
End Property
Public Sub FieldsUsage()
IntVar = 0
BoolVar = False
StrVar = "Hello World"
parameterFieldsUsage IntVar, BoolVar, StrVar
End Sub
Public Sub PropertiesUsage()
IntVarProp = 0
BoolVarProp = False
StrVarProp = "Hello World"
parameterProperiesUsage IntVarProp, BoolVarProp, StrVarProp
End Sub
Public Sub parameterFieldsUsage(IntVar As Integer, BoolVar As Boolean, StrVar As String)
''
End Sub
Public Sub parameterProperiesUsage(IntVar As Integer, BoolVar As Boolean, StrVar As String)
''
End Sub
C# code:
public int IntVarProp
{
//some comments for IntVarProp property header
get;
//some comments for IntVarProp property footer
//some comments for IntVarProp property header
set;
//some comments for IntVarProp property footer
}
public bool BoolVarProp
{
get;
set;
}
public string StrVarProp
{
get;
set;
}
public void FieldsUsage()
{
this.IntVarProp = 0;
this.BoolVarProp = false;
this.StrVarProp = "Hello World";
parameterFieldsUsage(this.IntVarProp, this.BoolVarProp, this.StrVarProp);
}
public void PropertiesUsage()
{
IntVarProp = 0;
BoolVarProp = false;
StrVarProp = "Hello World";
parameterProperiesUsage(IntVarProp, BoolVarProp, StrVarProp);
}
public void parameterFieldsUsage(int IntVar, bool BoolVar, string StrVar)
{
//
}
public void parameterProperiesUsage(int IntVar, bool BoolVar, string StrVar)
{
//
}
2.2. Off
No Auto-Implemented Properties will be generated from the original VB6 ones.
Original VB6 code:
Private IntVar As Integer
Private BoolVar As Boolean
Private StrVar As String
Public Property Let IntVarProp(value As Integer)
'some comments for IntVarProp property header'
IntVar = value
'some comments for IntVarProp property footer'
End Property
Public Property Get IntVarProp() As Integer
'some comments for IntVarProp property header'
IntVarProp = IntVar
'some comments for IntVarProp property footer'
End Property
Public Property Let BoolVarProp(value As Boolean)
BoolVar = value
End Property
Public Property Get BoolVarProp() As Boolean
BoolVarProp = BoolVar
End Property
Public Property Let StrVarProp(value As String)
StrVar = value
End Property
Public Property Get StrVarProp() As String
StrVarProp = StrVar
End Property
Public Sub FieldsUsage()
IntVar = 0
BoolVar = False
StrVar = "Hello World"
parameterFieldsUsage IntVar, BoolVar, StrVar
End Sub
Public Sub PropertiesUsage()
IntVarProp = 0
BoolVarProp = False
StrVarProp = "Hello World"
parameterProperiesUsage IntVarProp, BoolVarProp, StrVarProp
End Sub
Public Sub parameterFieldsUsage(IntVar As Integer, BoolVar As Boolean, StrVar As String)
''
End Sub
Public Sub parameterProperiesUsage(IntVar As Integer, BoolVar As Boolean, StrVar As String)
''
End Sub
C# code:
private int IntVar = 0;
private bool BoolVar = false;
private string StrVar = "";
public int IntVarProp
{
get
{
//some comments for IntVarProp property header
return IntVar;
//some comments for IntVarProp property footer
}
set
{
//some comments for IntVarProp property header
IntVar = value;
//some comments for IntVarProp property footer
}
}
public bool BoolVarProp
{
get
{
return BoolVar;
}
set
{
BoolVar = value;
}
}
public string StrVarProp
{
get
{
return StrVar;
}
set
{
StrVar = value;
}
}
public void FieldsUsage()
{
IntVar = 0;
BoolVar = false;
StrVar = "Hello World";
parameterFieldsUsage(IntVar, BoolVar, StrVar);
}
public void PropertiesUsage()
{
IntVarProp = 0;
BoolVarProp = false;
StrVarProp = "Hello World";
parameterProperiesUsage(IntVarProp, BoolVarProp, StrVarProp);
}
public void parameterFieldsUsage(int IntVar, bool BoolVar, string StrVar)
{
//
}
public void parameterProperiesUsage(int IntVar, bool BoolVar, string StrVar)
{
//
}
3. GoTo/GoSub Conversion
GoSub statements can be transformed to local functions only when C# is the target language.
3.1. Do not convert Go Sub statements
Choosing this option, the VBUC will not apply any special pattern recognition mechanism. GoSub statements are not supported by default in .NET structured code.
Original VB6 code:
Public Sub Main()
Dim i As Integer
i = 4
If i = 1 Then
GoSub printOne
ElseIf i = 2 Then
GoSub printTwo
ElseIf i = 3 Then
GoSub printThree
Else
GoSub SomethingElse
End If
GoTo exitLabel
printOne:
MsgBox "Value = 1"
Return
printTwo:
MsgBox "Value = 2"
Return
printThree:
MsgBox "Value = 3"
Return
SomethingElse:
MsgBox "Invalid Value!"
Return
exitLabel:
End Sub
C# code:
public static void Main()
{
int i = 4;
if (i == 1)
{
//UPGRADE_ISSUE: (1014) GoSub statement is not supported.
//UPGRADE_TODO: (1065) Error handling statement (Go Sub) could not be converted.
UpgradeHelpers.Helpers.NotUpgradedHelper.NotifyNotUpgradedElement("GoSub Label (printOne)");
}
else if (i == 2)
{
//UPGRADE_ISSUE: (1014) GoSub statement is not supported.
//UPGRADE_TODO: (1065) Error handling statement (Go Sub) could not be converted.
UpgradeHelpers.Helpers.NotUpgradedHelper.NotifyNotUpgradedElement("GoSub Label (printTwo)");
}
else if (i == 3)
{
//UPGRADE_ISSUE: (1014) GoSub statement is not supported.
//UPGRADE_TODO: (1065) Error handling statement (Go Sub) could not be converted.
UpgradeHelpers.Helpers.NotUpgradedHelper.NotifyNotUpgradedElement("GoSub Label (printThree)");
}
else
{
//UPGRADE_ISSUE: (1014) GoSub statement is not supported.
//UPGRADE_TODO: (1065) Error handling statement (Go Sub) could not be converted.
UpgradeHelpers.Helpers.NotUpgradedHelper.NotifyNotUpgradedElement("GoSub Label (SomethingElse)");
}
return;
printOne:
MessageBox.Show("Value = 1", AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly()));
//UPGRADE_WARNING: (2081) Return has a new behavior.
return;
printTwo:
MessageBox.Show("Value = 2", AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly()));
//UPGRADE_WARNING: (2081) Return has a new behavior.
return;
printThree:
MessageBox.Show("Value = 3", AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly()));
//UPGRADE_WARNING: (2081) Return has a new behavior.
return;
SomethingElse:
MessageBox.Show("Invalid Value!", AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly()));
//UPGRADE_WARNING: (2081) Return has a new behavior.
return;
}
3.2. Convert only GoSub statements to C# local function
Choosing this option, the VBUC will apply the special pattern recognition mechanism, to support the GoSub statement. This feature will only be applied when generating C# code.
General Description:
Visual Basic 6.0 provides the ability to jump into the code from one portion to another thru "labels" and create code that is not structured, according to the suggested coding patterns.
However, using GoSub and return statements gives the VB6 programmer certain functionality that used with certain restrictions can create "structured code".
By turning this feature on, the VBUC will recognize some of these patterns and will convert them to local functions for C#.
Original VB6 code:
Public Sub Main()
Dim i As Integer
i = 4
If i = 1 Then
GoSub printOne
ElseIf i = 2 Then
GoSub printTwo
ElseIf i = 3 Then
GoSub printThree
Else
GoSub SomethingElse
End If
GoTo exitLabel
printOne:
MsgBox "Value = 1"
Return
printTwo:
MsgBox "Value = 2"
Return
printThree:
MsgBox "Value = 3"
Return
SomethingElse:
MsgBox "Invalid Value!"
Return
exitLabel:
End Sub
C# code:
public static void Main()
{
int i = 4;
if (i == 1)
{
printOne();
}
else if (i == 2)
{
printTwo();
}
else if (i == 3)
{
printThree();
}
else
{
SomethingElse();
}
return;
void printOne()
{
MessageBox.Show("Value = 1", AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly()));
}
void printTwo()
{
MessageBox.Show("Value = 2", AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly()));
}
void printThree()
{
MessageBox.Show("Value = 3", AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly()));
}
void SomethingElse()
{
MessageBox.Show("Invalid Value!", AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly()));
}
}
3.3. Convert GoTo and GoSub statements to C# local function
Choosing this option, the VBUC will convert, when possible, GoTo and GoSub statements to internal functions. This feature is only available for C#.
Basic GoSub Statement
This feature will select GoSub/Return blocks to convert to functions. The label corresponding to a GoSub call must be at the same level as the Return statement. The GoSub statement will be replaced by a call to the function that checks for its return value to see if an exit condition was met (Exit Function or Exit Sub, for example).
Original VB6 Code
Public Sub BasicGoSubExample()
Dim i As Integer
i = 0
MsgBox i ' Display 0
GoSub Increase
MsgBox i ' Display 1
Exit Sub
Increase:
i = i + 1
Return
End Sub
Public Sub BasicGoSubExampleWithExit()
Dim i As Integer
i = 0
MsgBox i ' Display 0
GoSub Increase
MsgBox i ' Will not display
Exit Sub
Increase:
i = i + 1
If i = 1 Then
Exit Sub
End If
Return
End Sub
C# Code
public void BasicGoSubExample()
{
int i = 0;
MessageBox.Show(i.ToString(), ...)); // Display 0
if (label_Increase_function())
{
return;
}
MessageBox.Show(i.ToString(), ...)); // Display 1
return;
bool label_Increase_function()
{
i++;
return false;
}
}
public void BasicGoSubExampleWithExit()
{
int i = 0;
MessageBox.Show(i.ToString(), ...)); // Display 0
if (label_Increase_function())
{
return;
}
MessageBox.Show(i.ToString(), ...)); // Will not display
return;
bool label_Increase_function()
{
i++;
if (i == 1)
{
return true;
}
return false;
}
}
Basic GoTo Statement
In order to convert GoTo statements to functions, the VBUC will look for a pattern that starts with the label, and could end in another label, a Return statement, an Exit statement, or another GoTo statement. These blocks will be extracted as internal functions an calls to them placed where the GoTo statements. Since GoTo statements are one-way, they will be replaced with a call to the function followed by a return statement (if it's not the last line of of code), because the code after a GoTo statement should not be executed. Some code after a GoTo statement will be detected as dead code and will be commented.
Original VB6 Code
Public Sub BasicGoToExample()
Dim i As Integer
i = 0
MsgBox i ' Display 0
GoTo Increase
MsgBox i
Increase:
i = i + 1
End Sub
Public Sub BasicGoToExampleWithTwoGoTos()
Dim i As Integer
i = 0
MsgBox i ' Display 0
GoTo Increase
MsgBox i
Continue:
MsgBox i ' Display 1
Exit Sub
Increase:
i = i + 1
GoTo Continue
End Sub
C# Code
public void BasicGoToExample()
{
int i = 0;
MessageBox.Show(i.ToString(), ...)); // Display 0
label_Increase_function();
//UPGRADE_NOTE: (7001) The following code block (dead code detected by GoSub/GoTo feature) seems to be dead code...
//MessageBox.Show(i.ToString(), ...));
//label_Increase_function();
bool label_Increase_function()
{
i++;
return false;
}
}
public void BasicGoToExampleWithTwoGoTos()
{
int i = 0;
MessageBox.Show(i.ToString(), ...)); // Display 0
label_Increase_function();
//UPGRADE_NOTE: (7001) The following code block (dead code detected by GoSub/GoTo feature) seems to be dead code...
//MessageBox.Show(i.ToString(), ...));
//label_Continue_function();
//return;
bool label_Continue_function()
{
MessageBox.Show(i.ToString(), ...)); // Display 1
return true;
}
bool label_Increase_function()
{
i++;
return label_Continue_function();
}
}
This feature uses boolean return values to control the flow of the code so it is consistent with the original VB6 code. When one of these internal functions returns true, it is because the original method has ended (due to an Exit Sub or Exit Function), and so the return value is used to stop execution all the way back to the initical calling point. The way calls to internal functions are migrated varies depending on if the function is called from the main method, or from within another function.
Original VB6 Code
//Public Sub CodeFlowExample()
Dim i As Integer
i = 0
MsgBox i
GoSub Increase
MsgBox i
GoTo Decrease
Exit Sub
Multiply:
i = i * 2
Return
Increase:
i = i + 1
GoSub Divide
GoTo Multiply
Decrease:
i = i - 1
Exit Sub
Divide:
If i > 0 Then
i = i / 2
Else
Exit Sub
End If
Return
End Sub
C# Code
public void CodeFlowExample()
{
int i = 0;
MessageBox.Show(i.ToString(), ...));
if (label_Increase_function())
{
return;
}
MessageBox.Show(i.ToString(), ...));
label_Decrease_function();
return;
bool label_Multiply_function()
{
i *= 2;
return false;
}
bool label_Increase_function()
{
i++;
if (label_Divide_function())
{
return true;
}
return label_Multiply_function();
}
bool label_Decrease_function()
{
i--;
return true;
}
bool label_Divide_function()
{
if (i > 0)
{
i = Convert.ToInt32(i / 2d);
}
else
{
return true;
}
return false;
}
}
4. Discards
The discard feature was introduced in C# 7.0. It allows you to discard the result of an expression or variable you are not interested in or do not intend to use. Instead of assigning it to a variable you won't use, you can use the _ (underscore) symbol as a placeholder to discard the result.
4.1. On
When choosing this option, the VBUC will apply a special pattern recognition mechanism to apply the discard feature when necessary.
Original VB6 Code
Private Sub Form_Load()
Foo 2, 4
End Sub
Private Sub Foo(x As Integer, y As Integer)
Dim Sum As Integer
Dim Prod As Integer
Sum = x + y ' Variable used on MsgBox
Prod = x * y ' Variable not used
MsgBox Sum
End Sub
C# Code
private void Form_Load() => Foo(2, 4);
private void Foo(int x, int y)
{
int Sum = x + y; // Variable used on MsgBox
_ = x * y; // Variable not used
MessageBox.Show(Sum.ToString(), AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly()));
}
4.2. Off
Choosing this option, the VBUC will generate variables even if they are no longer necessary in the migrated code.
Original VB6 Code
Private Sub Form_Load()
Foo 2, 4
End Sub
Private Sub Foo(x As Integer, y As Integer)
Dim Sum As Integer
Dim Prod As Integer
Sum = x + y ' Variable used on MsgBox
Prod = x * y ' Variable not used
MsgBox Sum
End Sub
C# Code
private void Form_Load() => Foo(2, 4);
private void Foo(int x, int y)
{
int Sum = x + y; // Variable used on MsgBox
int Prod = x * y; // Variable not used
MessageBox.Show(Sum.ToString(), AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly()));
}