Origin:http://www.dotnet2themax.com/blogs/fbalena/CategoryView,category,Migrating%20from%20VB6.aspx
In this period I am actively researching the many problems you face when migrating VB6 apps to .NET. I don't like *migrating* applications, because I always prefer to rewrite them from scratch to leverate all the features of .NET and above all because the conversion wizard doesn't do a great job and produces ugly and non-maintenable code. Better, the wizard does a decent job, as long as it doesn't have to handle incompatibilities between VB6 and VB.NET.
Some of these incompatiblities, however, can be solved with a bit of imagination, especially now that VB2005 has features that weren't available before. For example, consider the "classic" problem of converting arrays with a lower index other than zero, a problem that has bothered all VB6 developers trying to porting complex code to VB.NET. Let's say you have this code:
Dim arr(1 to 10) as Integer
Dim i As Integer, prod As Integer, v As Variant
For i = LBound(arr) To UBound(arr)
arr(i) = i
Next
For Each v in arr
prod = prod * v
Next
The conversion wizard will replace the index "1" with the index "0", therefore the array has one more element. It's evident that, at the end of execution, the value of prod will be zero, whereas it should be equal to the factorial of 10. This sort of bug is quite subtle, and in practice you're forced to scrutinize your source code and re-test the application entirely. A better, manual approach consist of fixing the Dim statement to "shift" the array so that its first non-empty element has zero index, and then modify ALL the references to the elements of the array, to account for the shift:
Dim arr(0 to 10-1) as Integer
Dim i As Integer, prod As Integer
For i = LBound(arr) To UBound(arr)
arr(i - 1) = i
Next
Unfortunately, also this approach requires a lot of time and attention, and in some cases it can't be used, for example when the array is passed to a method that must work with arrays of any type (and whose code doesn't know that it has to shift the index). In yet other cases, the VB6 source code might use the value returned by LBound or UBound, and this code wouldn't work well after the migration.
The question is therefore: is it possible to convert this code to VB2005 without having to worry about all these issues? The solution has been relatively simple, thanks to generics and a few tricks with inheritance:
' Base class
Public
Class VBArrayBaseProtected Friend lowerIndex As Integer
Protected Friend upperIndex As Integer
End Class
' One dimensional array of type T
Public
Class VBArray( Of T)
Inherits VBArrayBase
Implements IEnumerable Dim items() As T Sub New ( ByVal lowerIndex As Integer , ByVal upperIndex As Integer )
Me .lowerIndex = lowerIndex
Me .upperIndex = upperIndex
ReDim items(upperIndex - lowerIndex)
End Sub
Public Function GetEnumerator() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
Return items.GetEnumerator()
End Function
Notice how simply the class provides support for For Each loops: it just has to return the IEnumerator object of the inner array. At this point I just needed to extend the LBound and UBound support to the new class. To do so, I created the following public module:
Public
Module ArrayFunctionsVB6Function LBound(ByVal arr As Array, Optional ByVal rank As Integer = 1) As Integer
Return Microsoft.VisualBasic.Information.LBound(arr, rank)
End Function
Function UBound(ByVal arr As Array, Optional ByVal rank As Integer = 1) As Integer
Return Microsoft.VisualBasic.Information.LBound(arr, rank)
End Function
Function LBound(ByVal arr As VBArrayBase, Optional ByVal rank As Integer = 1) As Integer
If rank = 1 Then
Return arr.lowerIndex
Else
Throw New IndexOutOfRangeException()
End If
End Function
Function UBound(ByVal arr As VBArrayBase, Optional ByVal rank As Integer = 1) As Integer
If rank = 1 Then
Return arr.upperIndex
Else
Throw New IndexOutOfRangeException()
End If
End Function
End Module
The module must expose two overloads for each method, one overload for standard arrays and the other for the new VBArray(Of T) class. Alas, you can't have a project that references two distinct modules - one in the VB compatiblity library and one in another DLL - where each module contains a different overload of the same method. In this case, only one of the two methods is visible to the main program.
Another interesting detail: the code inside the LBound and UBound methods needs to access the Friend members of the VBArray(Of T) class, but these methods can't have VBArray(of T) in the parameter list, because they aren't generic methods. This is the reason why I have the VBArray(Of T) class derive from VBArrayBase, where these Friend members are defined.
Thanks to the VBArray(Of T) class and the ArrayFunctionsVB6 module, you can migrate the VB6 code by changing only the DIM statement, as follows:
Dim arr As New VBArray(Of Short)(1, 10) ' Short instead of Integer
The remainder of the code will work flawlessly, exactly as in VB6, including the For Each loop and calls to LBound and UBound. Seeing is believing!
Get
Return items(index - lowerIndex)
End Get
Set ( ByVal value As T)
items(index - lowerIndex) = value
End Set
End Property