上一篇写了一下装箱拆箱的定义和IL分析,这一篇我们看下使用泛型和不使用泛型引发装箱拆箱的情况
1.使用非泛型集合时引发的装箱和拆箱操作
看下面的一段代码:
1
2
3
4
5
6
7
8
|
var array = new ArrayList(); array.Add(1); array.Add(2); foreach ( int value in array) { Console.WriteLine(“value is {0}”,value); } |
代码声明了一个ArrayList对象,向ArrayList中添加两个数字1,2;然后使用foreach将ArrayList中的元素打印到控制台。
在这个过程中会发生两次装箱操作和两次拆箱操作,在向ArrayList中添加int类型元素时会发生装箱,在使用foreach枚举ArrayList中的int类型元素时会发生拆箱操作,将object类型转换成int类型,在执行到Console.WriteLine时,还会执行两次的装箱操作;这一段代码执行了6次的装箱和拆箱操作;如果ArrayList的元素个数很多,执行装箱拆箱的操作会更多。
你可以通过使用ILSpy之类的工具查看IL代码的box,unbox指令查看装箱和拆箱的过程
2.使用泛型集合的情况
请看如下代码:
var list = new List< int >(); list.Add(1); list.Add(2); foreach ( int value in list) { Console.WriteLine( "value is {0}" , value); } |
代码和1中的代码的差别在于集合的类型使用了泛型的List,而非ArrayList;我们同样可以通过查看IL代码查看装箱拆箱的情况,上述代码只会在Console.WriteLine()方法时执行2次装箱操作,不需要拆箱操作。
可以看出泛型可以避免装箱拆箱带来的不必要的性能消耗;当然泛型的好处不止于此,泛型还可以增加程序的可读性,使程序更容易被复用等等。
本文使用的C#代码如下:
1 using System; 2 using System.Collections; 3 using System.Collections.Generic; 4 5 namespace boxOrUnbox 6 { 7 class Program 8 { 9 static void Main(string[] args) 10 { 11 //do nothing 12 } 13 14 static void Box() 15 { 16 object objValue = 9; 17 } 18 19 static void Unbox() 20 { 21 object objValue = 4; 22 int value = (int)objValue; 23 } 24 25 static void LookatArrayList() 26 { 27 var array = new ArrayList(); 28 array.Add(1); 29 array.Add(2); 30 31 foreach (int value in array) 32 { 33 Console.WriteLine("value is {0}", value); 34 } 35 } 36 37 static void LookatGenericList() 38 { 39 var list = new List<int>(); 40 list.Add(1); 41 list.Add(2); 42 43 foreach (int value in list) 44 { 45 Console.WriteLine("value is {0}", value); 46 } 47 } 48 } 49 }
C#的IL代码如下:
1 .class private auto ansi beforefieldinit boxOrUnbox.Program 2 extends [mscorlib]System.Object 3 { 4 // Methods 5 .method private hidebysig static 6 void Main ( 7 string[] args 8 ) cil managed 9 { 10 // Method begins at RVA 0x2050 11 // Code size 2 (0x2) 12 .maxstack 8 13 .entrypoint 14 15 IL_0000: nop 16 IL_0001: ret 17 } // end of method Program::Main 18 19 .method private hidebysig static 20 void Box () cil managed 21 { 22 // Method begins at RVA 0x2054 23 // Code size 10 (0xa) 24 .maxstack 1 25 .locals init ( 26 [0] object objValue 27 ) 28 29 IL_0000: nop 30 IL_0001: ldc.i4.s 9 31 IL_0003: box [mscorlib]System.Int32 32 IL_0008: stloc.0 33 IL_0009: ret 34 } // end of method Program::Box 35 36 .method private hidebysig static 37 void Unbox () cil managed 38 { 39 // Method begins at RVA 0x206c 40 // Code size 16 (0x10) 41 .maxstack 1 42 .locals init ( 43 [0] object objValue, 44 [1] int32 'value' 45 ) 46 47 IL_0000: nop 48 IL_0001: ldc.i4.4 49 IL_0002: box [mscorlib]System.Int32 50 IL_0007: stloc.0 51 IL_0008: ldloc.0 52 IL_0009: unbox.any [mscorlib]System.Int32 53 IL_000e: stloc.1 54 IL_000f: ret 55 } // end of method Program::Unbox 56 57 .method private hidebysig static 58 void LookatArrayList () cil managed 59 { 60 // Method begins at RVA 0x2088 61 // Code size 114 (0x72) 62 .maxstack 2 63 .locals init ( 64 [0] class [mscorlib]System.Collections.ArrayList 'array', 65 [1] int32 'value', 66 [2] class [mscorlib]System.Collections.IEnumerator CS$5$0000, 67 [3] bool CS$4$0001, 68 [4] class [mscorlib]System.IDisposable CS$0$0002 69 ) 70 71 IL_0000: nop 72 IL_0001: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor() 73 IL_0006: stloc.0 74 IL_0007: ldloc.0 75 IL_0008: ldc.i4.1 76 IL_0009: box [mscorlib]System.Int32 77 IL_000e: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object) 78 IL_0013: pop 79 IL_0014: ldloc.0 80 IL_0015: ldc.i4.2 81 IL_0016: box [mscorlib]System.Int32 82 IL_001b: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object) 83 IL_0020: pop 84 IL_0021: nop 85 IL_0022: ldloc.0 86 IL_0023: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.ArrayList::GetEnumerator() 87 IL_0028: stloc.2 88 .try 89 { 90 IL_0029: br.s IL_004a 91 // loop start (head: IL_004a) 92 IL_002b: ldloc.2 93 IL_002c: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current() 94 IL_0031: unbox.any [mscorlib]System.Int32 95 IL_0036: stloc.1 96 IL_0037: nop 97 IL_0038: ldstr "value is {0}" 98 IL_003d: ldloc.1 99 IL_003e: box [mscorlib]System.Int32 100 IL_0043: call void [mscorlib]System.Console::WriteLine(string, object) 101 IL_0048: nop 102 IL_0049: nop 103 104 IL_004a: ldloc.2 105 IL_004b: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() 106 IL_0050: stloc.3 107 IL_0051: ldloc.3 108 IL_0052: brtrue.s IL_002b 109 // end loop 110 111 IL_0054: leave.s IL_0070 112 } // end .try 113 finally 114 { 115 IL_0056: ldloc.2 116 IL_0057: isinst [mscorlib]System.IDisposable 117 IL_005c: stloc.s CS$0$0002 118 IL_005e: ldloc.s CS$0$0002 119 IL_0060: ldnull 120 IL_0061: ceq 121 IL_0063: stloc.3 122 IL_0064: ldloc.3 123 IL_0065: brtrue.s IL_006f 124 125 IL_0067: ldloc.s CS$0$0002 126 IL_0069: callvirt instance void [mscorlib]System.IDisposable::Dispose() 127 IL_006e: nop 128 129 IL_006f: endfinally 130 } // end handler 131 132 IL_0070: nop 133 IL_0071: ret 134 } // end of method Program::LookatArrayList 135 136 .method private hidebysig static 137 void LookatGenericList () cil managed 138 { 139 // Method begins at RVA 0x2118 140 // Code size 90 (0x5a) 141 .maxstack 2 142 .locals init ( 143 [0] class [mscorlib]System.Collections.Generic.List`1<int32> list, 144 [1] int32 'value', 145 [2] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> CS$5$0000, 146 [3] bool CS$4$0001 147 ) 148 149 IL_0000: nop 150 IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor() 151 IL_0006: stloc.0 152 IL_0007: ldloc.0 153 IL_0008: ldc.i4.1 154 IL_0009: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0) 155 IL_000e: nop 156 IL_000f: ldloc.0 157 IL_0010: ldc.i4.2 158 IL_0011: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0) 159 IL_0016: nop 160 IL_0017: nop 161 IL_0018: ldloc.0 162 IL_0019: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<int32>::GetEnumerator() 163 IL_001e: stloc.2 164 .try 165 { 166 IL_001f: br.s IL_003c 167 // loop start (head: IL_003c) 168 IL_0021: ldloca.s CS$5$0000 169 IL_0023: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current() 170 IL_0028: stloc.1 171 IL_0029: nop 172 IL_002a: ldstr "value is {0}" 173 IL_002f: ldloc.1 174 IL_0030: box [mscorlib]System.Int32 175 IL_0035: call void [mscorlib]System.Console::WriteLine(string, object) 176 IL_003a: nop 177 IL_003b: nop 178 179 IL_003c: ldloca.s CS$5$0000 180 IL_003e: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext() 181 IL_0043: stloc.3 182 IL_0044: ldloc.3 183 IL_0045: brtrue.s IL_0021 184 // end loop 185 186 IL_0047: leave.s IL_0058 187 } // end .try 188 finally 189 { 190 IL_0049: ldloca.s CS$5$0000 191 IL_004b: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> 192 IL_0051: callvirt instance void [mscorlib]System.IDisposable::Dispose() 193 IL_0056: nop 194 IL_0057: endfinally 195 } // end handler 196 197 IL_0058: nop 198 IL_0059: ret 199 } // end of method Program::LookatGenericList 200 201 .method public hidebysig specialname rtspecialname 202 instance void .ctor () cil managed 203 { 204 // Method begins at RVA 0x2190 205 // Code size 7 (0x7) 206 .maxstack 8 207 208 IL_0000: ldarg.0 209 IL_0001: call instance void [mscorlib]System.Object::.ctor() 210 IL_0006: ret 211 } // end of method Program::.ctor 212 213 } // end of class boxOrUnbox.Program
***********转摘:https://www.cnblogs.com/yukaizhao/archive/2004/01/13/csharp_box_unbox_2.html