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

前端之家收集整理的这篇文章主要介绍了.net – 使用array.resize而不是redim的原因前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我知道“redim”比“Array.Resize”更旧,但是不明白将后者用于前者的原因.
除非添加“保留”修改器,否则无法比较 ReDimArray.Resize<T>.

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

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

基本上这个:

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

……等于这个:

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

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

因此,让我们比较ReDim Preserve和Array< T>.

So which one to use?

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

VB.NET

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

CIL

.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 
}

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

所以人们可以争辩说它们本质上都是“相同的”,并且快速的benckmark(在这篇文章的最后可用)似乎证实了这一点.

但是,正如Hans Passant正确指出的那样,无论何时需要操作数组,都应该使用List<T>.

基准

Iterations: 10
MaxSize: 100000

Empty source array:

{ Method = ResizeArray1,Time = 00:00:05.6533126 }
{ Method = ResizeArray2,Time = 00:00:05.6973607 }

Growing source array:

{ Method = ResizeArray1,Time = 00:01:42.6964858 }
{ Method = ResizeArray2,Time = 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,.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

猜你在找的VB相关文章