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?
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: 100000Empty 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