Previous | Index | Next 

[HOWTO] Improve code generation with Variant variables and parameters

A VB6 Variant can contain either a scalar value (strings, numbers, dates, etc.) or an object. When converting variant expressions to VB.NET, VB Migration Partner takes a prudent approach and assumes that the variant might contain an object. This detail often causes the generation of unnecessarily verbose VB.NET code if a DefaultMemberSupport pragma has been emitted, or prevents VB Migration Partner from correctly generating a reference to the default property of an object.

Consider the following example:

        '## DefaultMemberSupport True
        Sub Test(ByVal tb As TextBox, ByVal name As Variant)
            name = tb
        End Sub

Here’s the converted .NET code:

        ' VB.NET
        Sub Test(ByVal tb As VB6TextBox, ByVal name As Object)
            SetDefaultMember6(name, tb.Text)
        End Sub
        // C#
        public void Test(VB6TextBox tb, object name)
        {
             VB6Helpers.SetDefaultMember(name, tb.Text);
        }

The above code perfectly reproduces the VB6 behavior, but it is unnecessarily verbose. In fact, it is clear that the VB6 developer meant name to be a scalar value (a string, to be precise), but VB Migration Partner can’t infer this fact. You can generate simpler code by letting VB Migration Partner that the Variant parameter is meant to contain a scalar value, as follows:

        '## DefaultMemberSupport True
        Sub Test(ByVal tb As TextBox, ByVal name As Variant)
              '## name.AssumeType String
              name = tb
        End Sub

which causes this code to be generated:

       ' VB.NET       
        Sub Test(ByVal tb As VB6TextBox, ByVal name As Object)
            name = tb.Text
        End Sub
        // C#
        public void Test(VB6TextBox tb, object name)
        {
             Name = tb.Text;
        }

The AssumeType pragma is also useful to force VB Migration Parter to generate a default property when calling a method. Unlike direct assignments – where the Set keyword is used to tell whether you are assigning a scalar value or an object – the action of passing a value to a method parameter is quite ambiguous under VB6. Consider this code:

        Sub Test(ByVal rs As ADODB.Recordset)
            ShowFieldValue rs("FirstName")
        End Sub
		
        Sub ShowFieldValue(ByVal fieldValue As Variant)
            MsgBox fieldValue
        End Sub

This is how the code is translated to .NET:

        ' VB.NET
        Public Sub Test(ByVal rs As ADODB.Recordset)
            ShowFieldValue(rs.Fields("FirstName"))
        End Sub
  
        Public Sub ShowFieldValue(ByVal fieldValue As Object)
            MsgBox6(fieldValue)
        End Sub
        // C#
        public void Test(ADODB.Recordset rs)
        {
              ShowFieldValue(rs.Fields["FirstName"]);
        }
        public void ShowFieldValue(object fieldValue)
        {
              VB6Helpers.MsgBox(fieldValue);
        }

Here’s the problem: VB Migration Partner fails to append the name of the default member of the ADODB.Field object (i.e. Value) in the call to the ShowFieldValue method. The reason is that the fieldValue parameter is defined as a Variant, therefore it might receive either a scalar or an object. You can help VB Migration Partner to generate better code by specifying that the parameter is always a scalar, as follows:

        Sub ShowFieldValue(ByVal fieldValue As Variant)
            '## fieldValue.AssumeType Single
            MsgBox fieldValue
        End Sub

Notice that the pragma argument is Single, but actually any scalar data type works. However Single works better than other types because it never forces conversions (as it happens with Double values when they are assigned a Date, or viceversa).

 

Previous | Index | Next