使用array.resize而不是redim的原因

gen*_*pos 5 .net vb.net arrays

我知道"redim"比"Array.Resize"更旧,但是不明白将后者用于前者的原因.

Bjø*_*sjå 2

除非添加修饰符,否则不可能比较ReDimArray.Resize<T>Preserve

Array.Resize不仅会分配一个新数组,还会将源数组中的所有项复制到目标数组中。

ReDim没有Preserve修饰符只会分配一个新数组。源数组中的所有项目都会丢失。

所以基本上是这样的:

Dim a As String() = {"item1", "item2"}
ReDim a(4 - 1) 'Double the size
'At this point, a contains 4 null references.
Run Code Online (Sandbox Code Playgroud)

...等于这个:

Dim a As String() = {"item1", "item2"}
a = New String(4 - 1) {} 'Double the size
'At this point, a contains 4 null references.
Run Code Online (Sandbox Code Playgroud)

您可以通过检查发布配置中生成的CIL代码并查找0x8D - newarr <etype>指令来验证这一点。了解了这一点,就很明显为什么它比Array.Resize<T>.

因此,我们来比较ReDim PreserveArray<T>

那么该使用哪一个呢?

让我们创建两个方法并查看CIL代码。

网络

Private Sub ResizeArray1(Of T)(ByRef a As T(), size As Int32)
    ReDim Preserve a(size - 1)
End Sub

Private Sub ResizeArray2(Of T)(ByRef a As T(), size As Int32)
    Array.Resize(a, size)
End Sub
Run Code Online (Sandbox Code Playgroud)

化学工业协会

.method private static void ResizeArray1<T>(!!T[]& a, int32 size) cil managed
{
    .maxstack 8
    L_0000: ldarg.0 
    L_0001: ldarg.0 
    L_0002: ldind.ref 
    L_0003: ldarg.1 
    L_0004: ldc.i4.1 
    L_0005: sub.ovf 
    L_0006: ldc.i4.1 
    L_0007: add.ovf 
    L_0008: newarr !!T
    L_000d: call class [mscorlib]System.Array [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Utils::CopyArray(class [mscorlib]System.Array, class [mscorlib]System.Array)
    L_0012: castclass !!T[]
    L_0017: stind.ref 
    L_0018: ret 
}

.method private static void ResizeArray2<T>(!!T[]& a, int32 size) cil managed
{
    .maxstack 8
    L_0000: ldarg.0 
    L_0001: ldarg.1 
    L_0002: call void [mscorlib]System.Array::Resize<!!T>(!!0[]&, int32)
    L_0007: ret 
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,ReDim Preserve最终作为Microsoft.VisualBasic.CompilerServices.Utils.CopyArray的调用指令。现在,如果您检查CopyArray(源代码在 RS 中不可用)和Array.Resize<T>,您将看到这两个方法最终都作为对Array.Copy<T> 的调用指令,而 Array.Copy<T> 是一个CLR方法。

因此,人们可以说它们本质上是“相同的”,并且快速基准(可在本文末尾找到)似乎证实了这一点。

然而,正如 Hans Passant 正确指出的那样,每当需要操作数组时,您应该使用List<T> 。


基准

迭代次数:10
最大尺寸:100000

空源数组:

{ 方法 = ResizeArray1,时间 = 00:00:05.6533126 }
{ 方法 = ResizeArray2,时间 = 00:00:05.6973607 }

不断增长的源数组:

{ 方法 = ResizeArray1,时间 = 00:01:42.6964858 }
{ 方法 = ResizeArray2,时间 = 00:01:42.1891668 }

Option Strict On

Public Module Program

    Friend Sub Main()
        Console.WriteLine("Warming up...")
        Program.Benchmark(iterations:=10, maxSize:=1000, warmUp:=True)
        Console.WriteLine("Warmup completed. Measurement started...")
        Program.Benchmark(iterations:=10, maxSize:=100000, warmUp:=False)
        Console.WriteLine()
        Console.WriteLine("Measurement completed. Press any key to exit.")
        Console.ReadKey()
    End Sub

    Private Sub Benchmark(iterations As Int32, maxSize As Int32, warmUp As Boolean)

        Dim watch As Stopwatch
        Dim a As String()

        'BY: EMPTY SOURCE ARRAY --------------------------------- 

        'Resize array #1

        watch = Stopwatch.StartNew()

        For i As Int32 = 1 To iterations
            For n As Int32 = 1 To maxSize
                a = Program.CreateArray(Of String)(0)
                Program.ResizeArray1(a, n)
            Next
        Next

        watch.Stop()

        If (Not warmUp) Then
            Console.WriteLine()
            Console.WriteLine(String.Format("R E S U L T"))
            Console.WriteLine()
            Console.WriteLine(String.Format("Iterations: {0}", iterations))
            Console.WriteLine(String.Format("   MaxSize: {0}", maxSize))
            Console.WriteLine()
            Console.WriteLine("Empty source array:")
            Console.WriteLine()
            Console.WriteLine(New With {.Method = "ResizeArray1", .Time = watch.Elapsed.ToString()})
        End If

        'Resize array #2

        watch = Stopwatch.StartNew()

        For i As Int32 = 1 To iterations
            For n As Int32 = 1 To maxSize
                a = CreateArray(Of String)(0)
                ResizeArray2(a, n)
            Next
        Next

        watch.Stop()

        If (Not warmUp) Then
            Console.WriteLine(New With {.Method = "ResizeArray2", .Time = watch.Elapsed.ToString()})
        End If

        'BY: GROWING SOURCE ARRAY -------------------------------

        'Resize array #1

        watch = Stopwatch.StartNew()
        a = Program.CreateArray(Of String)(0)

        For i As Int32 = 1 To iterations
            For n As Int32 = 1 To maxSize
                Program.ResizeArray1(a, n)
            Next
        Next

        watch.Stop()

        If (Not warmUp) Then
            Console.WriteLine()
            Console.WriteLine("Growing source array:")
            Console.WriteLine()
            Console.WriteLine(New With {.Method = "ResizeArray1", .Time = watch.Elapsed.ToString()})
        End If

        'Resize array #2

        watch = Stopwatch.StartNew()
        a = Program.CreateArray(Of String)(0)

        For i As Int32 = 1 To iterations
            For n As Int32 = 1 To maxSize
                Program.ResizeArray2(a, n)
            Next
        Next

        watch.Stop()

        If (Not warmUp) Then
            Console.WriteLine(New With {.Method = "ResizeArray2", .Time = watch.Elapsed.ToString()})
        End If

    End Sub

    Private Function CreateArray(Of T)(size As Int32) As T()
        Return New T(size - 1) {}
    End Function

    Private Sub ResizeArray1(Of T)(ByRef a As T(), size As Int32)
        ReDim Preserve a(size - 1)
    End Sub

    Private Sub ResizeArray2(Of T)(ByRef a As T(), size As Int32)
        Array.Resize(a, size)
    End Sub

End Module
Run Code Online (Sandbox Code Playgroud)