Array assignments work differently in VB6 and VB.NET. Under VB6, array assignments copy all the elements of the source array into the destination array; under VB.NET array assignments just copy the array pointer. This difference is a substantial one, as the following demonstrates:
Dim source(10) As Integer
Dim dest() As Integer
dest() = source()
source(0) = 123
Debug.Print dest(0)
Dim source(10) As Integer
Dim dest() As Integer
dest = source
source(0) = 123
Debug.Print(dest(0))
VB Migration Partner works around this difference by rendering all array assignments by means of the CloneArray6 helper method (in VB.NET) or the VB6Helpers.CloneArray method (in C#). In this specific case, the generated .NET code would be as follows:
Dim source(10) As Integer
Dim dest() As Integer
dest = CloneArray6(source)
source(0) = 123
Debug.Print(dest(0))
int[] source = new int[11];
int[] dest = null;
dest = VB6Helpers.CloneArray(source);
source[0] = 123;
VB6Helpers.DebugPrintLine(dest[0]);
In addition to enforcing the correct semantics with plain arrays, the CloneArray6 method ensures that arrays of structures are copied correctly, even if the structure contains arrays or nested structures.
Unfortunately, as sophisticated as it is, not even VB Migration Partner can automatically solve all the potential issues related to array copying. The following VB6 code shows an example of such issues:
Dim values(0 To 1) As Integer
Dim col As New Collection
values(0) = 111
col.Add(values)
values(0) = 222
col.Add(values)
Debug.Print col(1)(0) & "," & col(2)(0)
Even if it isn’t immediately obvious, VB6 passes a copy of the array to the Add method, therefore you can later change the array elements without affecting the array that is already stored inside the collection. Conversely, VB.NET and C# pass a reference of the array to the Add method, thus the migrated code behaves quite differently:
...
Debug.Print col(1)(0) & "," & col(2)(0)
You can work around this language difference in at least two ways, both of which require that you modify the VB6 code:
- You explicitly ReDim the array after the Add method, to force the compiler to create a new array reference:
Dim values(0 To 1) As Integer
Dim col As New Collection
values(0) = 111
col.Add(values)
ReDim values(0 To 1)
values(0) = 222
col.Add(values)
ReDim values(0 To 1)
...
This solution works well, however it adds a small overhead to the VB6 code that isn’t strictly necessary.
- you use the CloneArray6 method inside the call to the Add method. The VB6 version of this method does nothing, but when the code is migrated to .NET the method ensures that a copy of the array is passed to the Add method:
Dim values(0 To 1) As Integer
Dim col As New Collection
values(0) = 111
col.Add(CloneArray6(values))
values(0) = 222
col.Add(CloneArray6(values))
You also need to manually edit the VB6 code to insert an explicit call to the CloneArray6 method defined in VBMigrationPartner_Support module when copying an array of arrays – that is, a Variant array whose elements are arrays. Consider this VB6 code, which makes it evident that VB6 performs a “deep” copy of the array of arrays, i.e. it makes a copy of each individual array element:
Dim source(10) As Variant
Dim ints(5) As Integer
source(1) = ints
source(1)(1) = 111
Dim dest() As Variant
dest() = source()
dest(1)(1) = 222
Debug.Print source(1)(1) & "," & dest(1)(1)
VB Migration Partner migrates the above code to .NET as follows:
Dim source(10) As Object
Dim ints(5) As Integer
source(1) = ints
source(1)(1) = 111
Dim dest() As Object
dest = CloneArray6(source)
dest(1)(1) = 222
Debug.PrintLine6(source(1)(1) & "," & dest(1)(1))
object[] source = new object[11];
int[] ints = new int[6];
source[1] = ints;
source[1][1] = 111;
object[] dest = null;
dest = VB6Helpers.CloneArray(source);
dest[1][1] = 222;
VB6Helpers.DebugWriteLine(source[1][1] + "," & dest[1][1]);
The problem in this case is that, by default, the CloneArray6 method performs a “shallow” copy – in other words it creates a copy of the source array into a different array, but the individual elements of the result array still point to the values stored in the source array.
You can solve this problem by passing True in the second argument of the CloneArray6 method, which forces the method to perform a deep copy.
dest() = CloneArray6(source(), True)
Notice that a deep copy is significantly slower than a shallow copy, therefore you should pass True in the second argument only if you have ascertained that the converted .NET doesn’t behave like the original code.