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
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
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
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:
privateint IntVar =0;privatebool BoolVar =false;privatestring StrVar ="";publicint IntVarProp{ get { //some comments for IntVarProp property headerreturn IntVar; //some comments for IntVarProp property footer } set { //some comments for IntVarProp property header IntVar = value; //some comments for IntVarProp property footer }}publicbool BoolVarProp{ get {return BoolVar; } set { BoolVar = value; }}publicstring StrVarProp{ get {return StrVar; } set { StrVar = value; }}publicvoidFieldsUsage(){ IntVar =0; BoolVar =false; StrVar ="Hello World";parameterFieldsUsage(IntVar, BoolVar, StrVar);}publicvoidPropertiesUsage(){ IntVarProp =0; BoolVarProp =false; StrVarProp ="Hello World";parameterProperiesUsage(IntVarProp, BoolVarProp, StrVarProp);}publicvoidparameterFieldsUsage(int IntVar,bool BoolVar,string StrVar){ //}publicvoidparameterProperiesUsage(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:
publicstaticvoidMain(){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)"); }elseif (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)"); }elseif (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:
publicstaticvoidMain(){int i =4;if (i ==1) {printOne(); }elseif (i ==2) { printTwo(); }elseif (i ==3) { printThree(); }else {SomethingElse(); }return;voidprintOne() {MessageBox.Show("Value = 1",AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly())); }voidprintTwo() {MessageBox.Show("Value = 2",AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly())); }voidprintThree() {MessageBox.Show("Value = 3",AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly())); }voidSomethingElse() {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
publicvoidBasicGoSubExample(){int i =0;MessageBox.Show(i.ToString(),...)); // Display 0if (label_Increase_function()) {return; }MessageBox.Show(i.ToString(),...)); // Display 1return;boollabel_Increase_function() { i++;returnfalse; }}publicvoidBasicGoSubExampleWithExit(){int i =0;MessageBox.Show(i.ToString(),...)); // Display 0if (label_Increase_function()) {return; }MessageBox.Show(i.ToString(),...)); // Will not displayreturn;boollabel_Increase_function() { i++;if (i ==1) {returntrue; }returnfalse; }}
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
publicvoidBasicGoToExample(){int i =0;MessageBox.Show(i.ToString(),...)); // Display 0label_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();boollabel_Increase_function() { i++;returnfalse; }}publicvoidBasicGoToExampleWithTwoGoTos(){int i =0;MessageBox.Show(i.ToString(),...)); // Display 0label_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;boollabel_Continue_function() {MessageBox.Show(i.ToString(),...)); // Display 1returntrue; }boollabel_Increase_function() { i++;returnlabel_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
publicvoidCodeFlowExample(){int i =0;MessageBox.Show(i.ToString(),...));if (label_Increase_function()) {return; }MessageBox.Show(i.ToString(),...));label_Decrease_function();return;boollabel_Multiply_function() { i *=2;returnfalse; }boollabel_Increase_function() { i++;if (label_Divide_function()) {returntrue; }returnlabel_Multiply_function(); }boollabel_Decrease_function() { i--;returntrue; }boollabel_Divide_function() {if (i >0) { i =Convert.ToInt32(i /2d); }else {returntrue; }returnfalse; }}
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
privatevoidForm_Load() =>Foo(2,4);privatevoidFoo(int x,int y){int Sum = x + y; // Variable used on MsgBox _ = x * y; // Variable not usedMessageBox.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
privatevoidForm_Load() =>Foo(2,4);privatevoidFoo(int x,int y){int Sum = x + y; // Variable used on MsgBoxint Prod = x * y; // Variable not usedMessageBox.Show(Sum.ToString(),AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly()));}