为未指定元素类型的数组构建库函数

Building a library function for arrays of unspecified element type

将一个元素追加到数组的末尾有点复杂,因为它需要首先测试数组是否为空,如果不是,则测试它是否为空,最后调用有或没有 Preserve 的 ReDim 语句(指定 Preserve在所有情况下都不会受到伤害)。必须在我的一个应用程序中为具有各种类型元素的数组执行数百次此操作,其中大多数是本地生成的结构类型,这将使​​库函数的可用性变得非常可取。下面显示的 ArrayAppend 方法解决了具有特定元素类型(在本例中为整数)的数组的问题,但是 ArrayAppend 如何用于具有一般类型元素的数组?我试图传递参数“_ar() as Object”,但没有成功。也许我提交的代码有些过头了,但我觉得它应该足够完整,可以编译并准备接受更正。

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

这正是泛型的用途。您可能以前使用过通用的 class,例如 List(Of T),您可以在其中指定 运行 时的 T。您还可以编写一个泛型方法,而不是在泛型 class 中。在这种情况下,您可以这样做,然后在 运行 时间固定参数的类型。我还建议您将其编写为扩展方法,这样您就可以像调用实例方法一样在数组实例上调用它:

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

示例用法:

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))

输出:

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

因为该方法是通用的 - (Of T) 是它通用的原因 - 你可以用任何你喜欢的类型调用它,只要数组和你传递的新值是相同的类型,因为它们都在参数中声明为 T 类型。

声明数组参数的事实 ByRef 意味着您对该参数所做的任何更改都将反映在调用代码中。这意味着您调用该方法的数组将替换为您在该方法中创建的新数组。

因为这是一个扩展方法,所以在 Nothing 上调用它不会抛出 NullReferenceException。这个:

strings.Append("Hello")

只是语法糖,真正发生的是:

Append(strings, "Hello")