C#研究系列-List<>与ArrayList的几个研究心得及问题(上)
代码放在https://gist.github.com/921076 上了,看不到的请留言。
第一个心得,是我看某本书提到,IList用起来要比ArrayList快。
这里面用到了我上一篇博客提到的高精度计时器(在这里能看到代码 http://sunxiunan.com/?p=1829 )
在开始定义了两个类。
//---------------------
// public class List : IList, ICollection, IEnumerable, IList, ICollection, IEnumerable
class CFromList : List
{}
// public class ArrayList : IList, ICollection, IEnumerable, ICloneable
class CFromArrayList : ArrayList
{}
//---------------------
List和ArrayList的定义在注释中给出,可以看出来其实都差不多。ArrayList只是多了ICloneable,还少了几个泛型接口继承。
在后面代码中都用Add方法向list中添加int类型数据,然后通过foreach形式枚举数据,注意!枚举部分的代码是有问题的,我们在(下)中会提到。
这里还要推荐一个非常棒的工具ILSpy,是sharpdevelop开发的,强烈建议dotnet程序员都下载使用。
我把ILSpy disassemble出来的C#代码和IL代码分别列在后面。注意对于ArrayList的foreach语句,C#形式的代码与源代码有些差别(79 到96行),编译器加入一个IEnumerator enumerator2 = cFromArrayList.GetEnumerator();本地变量。
另外使用int num5 = (int)enumerator2.Current;这样访问iterator。而且还加入了IDisposable的finally部分。
再继续看IL代码部分,对于List形式,IL代码没有box装箱指令,而ArrayList在145行有个box指令,这是性能差别之一。
但是奇怪的是,在枚举部分,ILSpy生成的(以及ILDasm)IL代码,对于ArrayList和List而言,基本上差别不大,一样也有对
MoveNext和Current以及IDisposable接口的调用。
只不过ArrayList多出unbox和box的指令。
运行结果如我们所料,List要比ArrayList快不少。
但是我们在枚举部分的代码是有问题的,我明天在(下)中会介绍。
// public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerableclass CFromList : List<int>{}// public class ArrayList : IList, ICollection, IEnumerable, ICloneableclass CFromArrayList : ArrayList{}public partial class Form1 : Form{private void button1_Click(object sender, EventArgs e){CFromList list1 = new CFromList();CFromArrayList list2 = new CFromArrayList();////////////////////////////HighResolutionTimer timera = new HighResolutionTimer();for (int i = 0; i < 100000; i++){list1.Add(i - 99999);}Int64 reta = timera.Stop();////////////////////////////HighResolutionTimer timerb = new HighResolutionTimer();for (int i = 0; i < 100000; i++){list2.Add(i - 99999);}Int64 retb = timerb.Stop();////////////////////////////int index = 0;HighResolutionTimer timer1 = new HighResolutionTimer();foreach (int elem1 in list1){list1[index++] = elem1 + 99;}Int64 ret1 = timer1.Stop();////////////////////////////index = 0;HighResolutionTimer timer2 = new HighResolutionTimer();foreach (int elem2 in list2){list2[index++] = elem2 + 99;}Int64 ret2 = timer2.Stop();////////////////////////////}}///////////////////////////////////////////////////////// result from ILSpyCFromList cFromList = new CFromList();CFromArrayList cFromArrayList = new CFromArrayList();HighResolutionTimer highResolutionTimer = new HighResolutionTimer();for (int i = 0; i < 100000; i++){cFromList.Add(i - 99999);}long num = highResolutionTimer.Stop();HighResolutionTimer highResolutionTimer2 = new HighResolutionTimer();for (int i = 0; i < 100000; i++){cFromArrayList.Add(i - 99999);}long num2 = highResolutionTimer2.Stop();int num3 = 0;HighResolutionTimer highResolutionTimer3 = new HighResolutionTimer();foreach (int current in cFromList){cFromList[num3++] = current + 99;}long num4 = highResolutionTimer3.Stop();num3 = 0;HighResolutionTimer highResolutionTimer4 = new HighResolutionTimer();IEnumerator enumerator2 = cFromArrayList.GetEnumerator();try{while (enumerator2.MoveNext()){int num5 = (int)enumerator2.Current;cFromArrayList[num3++] = num5 + 99;}}finally{IDisposable disposable = enumerator2 as IDisposable;if (disposable != null){disposable.Dispose();}}long num6 = highResolutionTimer4.Stop();//////////////////////////////////////////////////// result from ILSpy IL formatIL_0000: nopIL_0001: newobj instance void WindowsFormsApplication1.CFromList::.ctor()IL_0006: stloc.0IL_0007: newobj instance void WindowsFormsApplication1.CFromArrayList::.ctor()IL_000c: stloc.1IL_000d: newobj instance void WindowsFormsApplication1.HighResolutionTimer::.ctor()IL_0012: stloc.2IL_0013: ldc.i4.0IL_0014: stloc.3IL_0015: br.s IL_002b// loop start (head: IL_002b)IL_0017: nopIL_0018: ldloc.0IL_0019: ldloc.3IL_001a: ldc.i4 99999IL_001f: subIL_0020: callvirt instance void [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)IL_0025: nopIL_0026: nopIL_0027: ldloc.3IL_0028: ldc.i4.1IL_0029: addIL_002a: stloc.3IL_002b: ldloc.3IL_002c: ldc.i4 100000IL_0031: cltIL_0033: stloc.s 17IL_0035: ldloc.s 17IL_0037: brtrue.s IL_0017// end loopIL_0039: ldloc.2IL_003a: callvirt instance int64 WindowsFormsApplication1.HighResolutionTimer::Stop()IL_003f: stloc.s 4IL_0041: newobj instance void WindowsFormsApplication1.HighResolutionTimer::.ctor()IL_0046: stloc.s 5IL_0048: ldc.i4.0IL_0049: stloc.3IL_004a: br.s IL_0065// loop start (head: IL_0065)IL_004c: nopIL_004d: ldloc.1IL_004e: ldloc.3IL_004f: ldc.i4 99999IL_0054: subIL_0055: box int32IL_005a: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)IL_005f: popIL_0060: nopIL_0061: ldloc.3IL_0062: ldc.i4.1IL_0063: addIL_0064: stloc.3IL_0065: ldloc.3IL_0066: ldc.i4 100000IL_006b: cltIL_006d: stloc.s 17IL_006f: ldloc.s 17IL_0071: brtrue.s IL_004c// end loopIL_0073: ldloc.s 5IL_0075: callvirt instance int64 WindowsFormsApplication1.HighResolutionTimer::Stop()IL_007a: stloc.s 6IL_007c: ldc.i4.0IL_007d: stloc.s 7IL_007f: newobj instance void WindowsFormsApplication1.HighResolutionTimer::.ctor()IL_0084: stloc.s 8IL_0086: nopIL_0087: ldloc.0IL_0088: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> [mscorlib]System.Collections.Generic.List`1<int32>::GetEnumerator()IL_008d: stloc.s 18.try {IL_008f: br.s IL_00af// loop start (head: IL_00af)IL_0091: ldloca.s 18IL_0093: call instance !0 [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current()IL_0098: stloc.s 9IL_009a: nopIL_009b: ldloc.0IL_009c: ldloc.s 7IL_009e: dupIL_009f: ldc.i4.1IL_00a0: addIL_00a1: stloc.s 7IL_00a3: ldloc.s 9IL_00a5: ldc.i4.s 99IL_00a7: addIL_00a8: callvirt instance void [mscorlib]System.Collections.Generic.List`1<int32>::set_Item(int32, !0)IL_00ad: nopIL_00ae: nopIL_00af: ldloca.s 18IL_00b1: call instance bool [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext()IL_00b6: stloc.s 17IL_00b8: ldloc.s 17IL_00ba: brtrue.s IL_0091// end loopIL_00bc: leave.s IL_00cd} // end .tryfinally {IL_00be: ldloca.s 18IL_00c0: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>IL_00c6: callvirt instance void [mscorlib]System.IDisposable::Dispose()IL_00cb: nopIL_00cc: endfinally} // end handlerIL_00cd: nopIL_00ce: ldloc.s 8IL_00d0: callvirt instance int64 WindowsFormsApplication1.HighResolutionTimer::Stop()IL_00d5: stloc.s 10IL_00d7: ldc.i4.0IL_00d8: stloc.s 7IL_00da: newobj instance void WindowsFormsApplication1.HighResolutionTimer::.ctor()IL_00df: stloc.s 11IL_00e1: nopIL_00e2: ldloc.1IL_00e3: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.ArrayList::GetEnumerator()IL_00e8: stloc.s 19.try {IL_00ea: br.s IL_0114// loop start (head: IL_0114)IL_00ec: ldloc.s 19IL_00ee: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()IL_00f3: unbox.any int32IL_00f8: stloc.s 12IL_00fa: nopIL_00fb: ldloc.1IL_00fc: ldloc.s 7IL_00fe: dupIL_00ff: ldc.i4.1IL_0100: addIL_0101: stloc.s 7IL_0103: ldloc.s 12IL_0105: ldc.i4.s 99IL_0107: addIL_0108: box int32IL_010d: callvirt instance void [mscorlib]System.Collections.ArrayList::set_Item(int32, object)IL_0112: nopIL_0113: nopIL_0114: ldloc.s 19IL_0116: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()IL_011b: stloc.s 17IL_011d: ldloc.s 17IL_011f: brtrue.s IL_00ec// end loopIL_0121: leave.s IL_0140} // end .tryfinally {IL_0123: ldloc.s 19IL_0125: isinst class [mscorlib]System.IDisposableIL_012a: stloc.s 20IL_012c: ldloc.s 20IL_012e: ldnullIL_012f: ceqIL_0131: stloc.s 17IL_0133: ldloc.s 17IL_0135: brtrue.s IL_013fIL_0137: ldloc.s 20IL_0139: callvirt instance void [mscorlib]System.IDisposable::Dispose()IL_013e: nopIL_013f: endfinally} // end handlerIL_0140: nopIL_0141: ldloc.s 11IL_0143: callvirt instance int64 WindowsFormsApplication1.HighResolutionTimer::Stop()IL_0148: stloc.s 13