Home > Enterprise >  Building a library function for arrays of unspecified element type
Building a library function for arrays of unspecified element type

Time:05-03

Appending an element to the end of an array is slightly involved as it requires first testing if the array is Nothing, then if not, testing if it is empty and finally invoking the ReDim statement with or without Preserve (specifying Preserve in all cases won't hurt). Having to do this in one of my applications hundreds of times for arrays having elements of a variety of types, most of them home-grown Structure types, would make the availability of a library function very desirable. The ArrayAppend method shown below solves the problem for arrays with specific element types, integer in this case, but how could ArrayAppend be phrased for arrays with elements of a general type? I tried to pass the argument " _ar() as Object ", but no luck. Perhaps I have gone overboard with the code I am submitting, but I felt it ought to be complete enough to compile and am prepared to stand corrected.

Option Strict On
Option Explicit On

Public Class CUtils

    Public Shared Function ArrayAppend(ByVal _ar() As Integer,
                                       ByVal _element As Integer) As Integer()
        '
        If Not _ar Is Nothing Then
            Dim Len As Integer = _ar.Length
            If Len = 0 Then
                ReDim _ar(0)
                _ar(0) = _element
            Else
                ReDim Preserve _ar(Len)
                _ar(_ar.Length - 1) = _element
            End If
        Else
            ReDim _ar(0)
            _ar(0) = _element
        End If
        Return _ar
        '
    End Function ' ArrayAppend
    '
    Public Shared Sub ArrayShow(ByVal _ar() As Integer)
        '
        If Not _ar Is Nothing Then
            For Each item As Integer In _ar
                If item = _ar.Last Then
                    Console.Write(item & vbCrLf)
                Else
                    Console.Write(item & " ,")
                End If
            Next
        Else
            Console.WriteLine("Nothing")
        End If

        '
    End Sub ' ArrayShow
    '
End Class ' CUtils

Option Strict On
Option Explicit On

Module MyApp

    Sub Main()
        Dim arInt() As Integer = Nothing

        Console.WriteLine("1. Appending to a Nothing array of integers:")
        CUtils.ArrayShow(arInt)
        arInt = CUtils.ArrayAppend(arInt, 987)
        CUtils.ArrayShow(arInt)

        Console.WriteLine("2. Appending to an existing non-empty array of integers:")
        arInt = {1, 2, 3}
        CUtils.ArrayShow(arInt)
        arInt = CUtils.ArrayAppend(arInt, 987)
        CUtils.ArrayShow(arInt)

        Console.WriteLine("3. Appending to an existing empty array of integers:")
        arInt = {}
        CUtils.ArrayShow(arInt)
        arInt = CUtils.ArrayAppend(arInt, 987)
        CUtils.ArrayShow(arInt)
    End Sub

End Module ' MyApp

CodePudding user response:

This is exactly what generics are for. You have presumably used a generic class like List(Of T) before, where you get to specify what T is at run time. You can also write a generic method without it being in a generic class. In this case, you can do that and then fix the type of the parameters at run time. I would also recommend that you write it as an extension method, so you can then call it on an array instance as though it were an instance method:

Imports System.Runtime.CompilerServices

Public Module ArrayExtensions

    <Extension>
    Public Sub Append(Of T)(ByRef source As T(), element As T)
        'If source is Nothing then new upper bound is zero.
        'Otherwise, new upper bound is current Length, i.e. current upper bound   1.
        Dim upperBound = If(source?.Length, 0)

        ReDim Preserve source(upperBound)

        source(upperBound) = element
    End Sub

End Module

Sample usage:

Dim strings As String() = Nothing
Dim integers As Integer() = Nothing

strings.Append("Hello")
integers.Append(123)

Console.WriteLine("strings: " & String.Join(", ", strings))
Console.WriteLine("integers: " & String.Join(", ", integers))

strings.Append("World")
integers.Append(456)

Console.WriteLine("strings: " & String.Join(", ", strings))
Console.WriteLine("integers: " & String.Join(", ", integers))

Output:

strings: Hello
integers: 123
strings: Hello, World
integers: 123, 456

Because that method is generic - the (Of T) is what makes it generic - you can call it with any type you like, as long as the array and the new value you pass are the same type, because they are both declared as type T in the parameters.

The fact that the array parameter is declared ByRef means that any changes you make to that parameter will be reflected in the calling code. That means that the array you called the method on will be replaced with the new array you're creating in the method.

Because this is an extension method, calling it on Nothing will not throw a NullReferenceException. This:

strings.Append("Hello")

is just syntactic sugar and what's really happening is this:

Append(strings, "Hello")
  • Related