Upgrading Arrays 

    Background

    In VB6 an array is a variable that contains a finite number of elements that have a common name and data type. Each element of an array is identified by a unique index number. Changes made to one element of an array don't affect the other elements.

    The Individual elements of an array are identified using an index.

    Arrays have upper and lower bounds and the elements have to lie within those bounds. Each index number in an array is allocated individual memory space and therefore users must evade declaring arrays of larger size than required. Arrays can de declare of any of the basic data types including variant, user-defined types and object variables. The individual elements of an array are all of the same data type.

    Declaring arrays

    Arrays occupy space in memory. The programmer specifies the array type and the number of elements required by the array so that the compiler may reserve the appropriate amount of memory. Arrays may be declared as Public (in a code module), module or local. Module arrays are declared in the general declarations using keyword Dim or Private. Local arrays are declared in a procedure using Dim or Static. Array must be declared explicitly with keyword "As".

    There are two types of arrays in Visual Basic namely:

    Fixed-size array : The size of array always remains the same-size doesn't change during the program execution.

    Dynamic array : The size of the array can be changed at the run time- size changes during the program execution

    Fixed-sized Arrays

    When an upper bound is specified in the declaration, a Fixed-array is created. The upper limit should always be within the range of long data type.

    Declaring a fixed-array

    Dim numbers(5) As Integer

    In the above snippet, numbers is the name of the array, and the number 6 included in the parentheses is the upper limit of the array. The above declaration creates an array with 6 elements, with index numbers running from 0 to 5.

    If we want to specify the lower limit, then the parentheses should include both the lower and upper limit along with the To keyword. An example for this is given below.

    Dim numbers (1 To 6 ) As Integer

    In the above statement, an array of 10 elements is declared but with indexes running from 1 to 6.

    A public array can be declared using the keyword Public instead of Dim as shown below.

    Public numbers(5) As Integer

    Multidimensional Arrays

    Arrays can have multiple dimensions. A common use of multidimensional arrays is to represent tables of values consisting of information arranged in rows and columns. To identify a particular table element, we must specify two indexes: The first (by convention) identifies the element's row and the second (by convention) identifies the element's column.

    Tables or arrays that require two indexes to identify a particular element are called two dimensional arrays. Note that multidimensional arrays can have more than two dimensions. Visual Basic supports at least 60 array dimensions, but most people will need to use more than two or three dimensional-arrays.

    The following statement declares a two-dimensional array 50 by 50 array within a procedure.

    Dim AvgMarks ( 50, 50)

    It is also possible to define the lower limits for one or both the dimensions as for fixed size arrays. An example for this is given here.

    Dim Marks ( 101 To 200, 1 To 100)

    An example for three dimensional-array with defined lower limits is given below.

    Dim Details( 101 To 200, 1 To 100, 1 To 100)

    Static and dynamic arrays

    Basically, you can create either static or dynamic arrays. Static arrays must include a fixed number of items, and this number must be known at compile time so that the compiler can set aside the necessary amount of memory. You create a static array using a Dim statement with a constant argument:

    ' This is a static array.
    Dim Names(100) As String

    Visual Basic starts indexing the array with 0. Therefore, the preceding array actually holds 101 items.

    Most programs don't use static arrays because programmers rarely know at compile time how many items you need and also because static arrays can't be resized during execution. Both these issues are solved by dynamic arrays. You declare and create dynamic arrays in two distinct steps. In general, you declare the array to account for its visibility (for example, at the beginning of a module if you want to make it visible by all the procedures of the module) using a Dim command with an empty pair of brackets. Then you create the array when you actually need it, using a ReDim statement:

    ' An array defined in a BAS module (with Private scope)
    Dim Customers() As String
    //...
    Sub Main()
    ' Here you create the array.
    ReDim Customer(1000) As String
    End Sub

    If you're creating an array that's local to a procedure, you can do everything with a single ReDim statement:

    Sub PrintReport()
    ' This array is visible only to the procedure.
    ReDim Customers(1000) As String
    ' ...
    End Sub

    If you don't specify the lower index of an array, Visual Basic assumes it to be 0, unless an Option Base 1 statement is placed at the beginning of the module. My suggestion is this: Never use an Option Base statement because it makes code reuse more difficult. (You can't cut and paste routines without worrying about the current Option Base.) If you want to explicitly use a lower index different from 0, use this syntax instead:

    ReDim Customers(1 To 1000) As String

    Dynamic arrays can be re-created at will, each time with a different number of items. When you re-create a dynamic array, its contents are reset to 0 (or to an empty string) and you lose the data it contains. If you want to resize an array without losing its contents, use the ReDim Preserve command:

    ReDim Preserve Customers(2000) As String

    When you're resizing an array, you can't change the number of its dimensions nor the type of the values it contains. Moreover, when you're using ReDim Preserve on a multidimensional array, you can resize only its last dimension:

    ReDim Cells(1 To 100, 10) As Integer
    //...
    ReDim Preserve Cells(1 To 100, 20) As Integer ' This works.
    ReDim Preserve Cells(1 To 200, 20) As Integer ' This doesn't.

    Finally, you can destroy an array using the Erase statement. If the array is dynamic, Visual Basic releases the memory allocated for its elements (and you can't read or write them any longer); if the array is static, its elements are set to 0 or to empty strings.

    You can use the LBound and UBound functions to retrieve the lower and upper indices. If the array has two or more dimensions, you need to pass a second argument to these functions to specify the dimension you need:

    Print LBound(Cells, 1) ' Displays 1, lower index of 1st dimension
    Print LBound(Cells) ' Same as above
    Print UBound(Cells, 2) ' Displays 20, upper index of 2nd dimension
    ' Evaluate total number of elements.
    NumEls = (UBound(Cells) _ LBound(Cells) + 1) * _
    (UBound(Cells, 2) _ LBound(Cells, 2) + 1)

    Arrays within UDTs

    UDT structures can include both static and dynamic arrays. Here's a sample structure that contains both types:

    Type MyUDT
      StaticArr(100) As Long
      DynamicArr() As Long
    End Type
    '...
    Dim udt As MyUDT
    ' You must DIMension the dynamic array before using it.
    ReDim udt.DynamicArr(100) As Long
    ' You don't have to do that with static arrays.
    udt.StaticArr(1) = 1234

    The memory needed by a static array is allocated within the UDT structure; for example, the StaticArr array in the preceding code snippet takes exactly 400 bytes. Conversely, a dynamic array in a UDT takes only 4 bytes, which form a pointer to the memory area where the actual data is stored. Dynamic arrays are advantageous when each individual UDT variable might host a different number of array items. As with all dynamic arrays, if you don't dimension a dynamic array within a UDT before accessing its items, you get an error 9—"Subscript out of range."

    Migration to VB.NET

    Array declarations

    In VB.NET array declarations are identical to VB6

    VB6

    ' Fixed Sized Arrays
    Dim numbers(5) As Integer

    'The following statement declares a two-dimensional
    'array 50 by 50 array within a procedure.
    Dim AvgMarks(50, 50) As Object

    VB.NET

    ' Fixed Sized Arrays
    Dim numbers(5) As Integer

    'The following statement declares a two-dimensional
    'array 50 by 50 array within a procedure.
    Dim AvgMarks(50, 50) As Object



    C#


    Notice that in C# the declaration says 6. That is because elements in VB6 went from 0 to 5 that is a total of 6 elements.
    // Fixed Sized Arrays
    int[] numbers = new int[6];

    Notice that the C# declaration says 51 that is because in VB6 arrays went from 0 to 50 and that is 51 elements.
    // The following statement declares a two-dimensional
    // array 50 by 50 array within a procedure.

    object[, ] AvgMarks = new object[51, 51];

    Arrays with lower limits or upper limits require an slightly different migration


    VB6

    Dim Marks(101 To 200, 1 To 100)
    'An example for three dimensional-array with defined lower limits is given below.
    Dim Details(101 To 200, 1 To 100, 1 To 100)

    In both VB.NET and C# a the .NET Framework Array class is used. In .NET the use a lower bound or upper different than 0 the Array class must used.  The first argument to the CreateInstance method is the size of the dimensions,
    and the second parameter is the start index for each dimension

    VB.NET

    Dim Marks As Array = Array.CreateInstance(GetType(Object), New Integer() {100, 100}, New Integer() {101, 1})
    Dim Details As Array = Array.CreateInstance(GetType(Object), New Integer() {100, 100, 100}, New Integer() {101, 1, 1})

    C#

    Array Marks = Array.CreateInstance(typeof(object), new int[]{100, 100}, new int[]{101, 1});
    Dim Details As Array = Array.CreateInstance(GetType(Object), New Integer() {100, 100, 100}, New Integer() {101, 1, 1})

    Array Initialization

    In VB6 numeric arrays are initialized to 0, string arrays are initialized to empty strings.  In C# string arrays are initialized to null. The ArraysHelper class provides a quick way to perform that initialization.

    VB6

    Dim Names(100) As String

    C#

    // Visual Basic starts indexing the array with 0.
    // Therefore, the preceding array actually holds 101 items.
    string[] Names = ArraysHelper.InitializeArray<string>(101);

    Redims

    In VB you can do multiple redims for the same variable.
    If the redim does not have preserve then it will discard the data.
    VB.NET supports both the Redim and the Redim Preserve syntax. For C# if the array is small the VBUC will just generate a small .NET native C# initializer. The VBUC will generate a calls to helper ArraysHelper.RedimPreserve to perform the redim preserve functionality.

    VB6

    ReDim Customers(1 To 1000) As String
    ReDim Customers(2) As String
    Customers(0) = "John"
    Customers(1) = "Browne"
    ' The following redim will discard the data
    ReDim Customers(2) As String
    Customers(0) = "John"
    Customers(1) = "Browne"
    ' The following redim will discard the data
    ReDim Preserve Customers(3) As String

    VB.NET

    Dim Customers(999) As String

    ReDim Customers(2)
    Customers(0) = "John"
    Customers(1) = "Browne"
    ' The following redim will discard the data
    ReDim Customers(2)

    Customers(0) = "John"
    Customers(1) = "Browne"
    ' The following redim will discard the data
    ReDim Preserve Customers(3)

    C#


    string[] Customers = ArraysHelper.InitializeArray<string>(1000);
    Customers = new string[]{"", "", ""};
    Customers[0] = "John";
    Customers[1] = "Browne";
    // The following redim will discard the data
    Customers = new string[]{"", "", ""};
    Customers[0] = "John";
    Customers[1] = "Browne";
    // The following redim will discard the data
    Customers = ArraysHelper.RedimPreserve(Customers, new int[]{4});

    In C# if the array is too big for example for VB6:
    ReDim Customers(100) As String
    In C# a helper method will be used because an array initializer will be too long:
    Customers = ArraysHelper.InitializeArray<string>(101);

    Lower Bounds to Zero

    In C# lower bounds they are always 0. Several transformations are applied
    to correct the arrays’ declarations and the indexes used while accessing either arrays or collections.

    Brackets Generation for Array Access

    Arrays in VB6 are accessed with round parenthesis, in the same way as subroutines and functions.
    For C# this array access expressions must be recognized, differentiating them from function
    invocations, and generated with the appropriate syntax.


    Array dims and Redims

    When migrating from VB6 to C# you should notice that C# arrays are quite inflexible. They only support lower bound equal to zero and arrays with a constant amount of dimensions (although they can change their magnitudes). However the .NET
    class Array allows representing flexible arrays that can be re-dimensioned, and their lower bounds
    changed.
    The following modifications are supported by the VBUC:

    • Declaration and access corrections: every array is inspected during the typing phase to
    determine what kind of dimensions it is being used with. Based on this information both the
    declaration and uses of each array are corrected.

    • Use of Array class for complex cases: when an array has an inconsistent use of
    dimensions or lower bounds different to zero or one, they get converted to the class “Array”,
    which allows re-dimensioning and changing the lower bounds. All its uses are also modified.

    Redim statements: redim statements get converted to an assignment of the array to a
    construction of the new array:
    <arrayref> = new <ArrayType>(<NewDimensions>).
    If the array was declared by using the class “Array” an invocation to Array.CreateInstance is
    used to create the new array.
    When the “preserve” keyword was used, a statement is generated after the assignment to
    copy the original information into the new array instance.

    Arrays Advanced Conversion


    The arrays conversion can be particularly complex because they can be dimensioned and redimensioned several times with different bounds. The option base 0 or 1 is also a source of
    confusion, changing the default lower bounds that can be combined and interchanged later in some
    array references.
    The .NET arrays must be regular, must have a lower bound equal to zero and cannot change their
    amount of dimensions, although they might change the dimension magnitudes. In order to resolve
    these inconsistencies, an analysis is performed upon all the arrays, declarations, redims and
    accesses, figuring out what the array bounds should be and whether they are used in a regular way
    or not. This information allows the VBUC to make decisions about how to declare the array in .NET,
    how to do the re-dimensioning processes and whether to apply corrections to the indexes used to
    access the array or not.
    For the most difficult cases, where a reference to array is used with inconsistent dimensions or
    inconsistent lower bounds, the class Array is used to represent a much more flexible concept of the
    data type and all its references are modified accordingly.

    Multidimensional Arrays

    In VB6, arrays can mutate and change dimensions and magnitudes, while in .Net they must be
    declared in the simplest way that will be able to represent all their previous behaviors. The current
    typer version (after VBUC 7.2) identifies several new patterns related to the multiple dimensional arrays and makes
    much better decisions regarding this area

    EWIS related

    WARNING #1042
    EWI #1056 Redim Removed
    WARNING #1063

    Important Resources

    Download VBUC Free Trial
    Download  Now

    It's time to eradicate VB6
    ROI of Eradicating VB6

    8 Proven Tips for
    Planning a Successful Migration

    Learn More