再谈C#的装箱和拆箱
上一篇写了一下装箱拆箱的定义和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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | using System; using System.Collections; using System.Collections.Generic; namespace boxOrUnbox { class Program { static void Main( string [] args) { //do nothing } static void Box() { object objValue = 9; } static void Unbox() { object objValue = 4; int value = ( int )objValue; } static void LookatArrayList() { var array = new ArrayList(); array.Add(1); array.Add(2); foreach ( int value in array) { Console.WriteLine( "value is {0}" , value); } } static void LookatGenericList() { var list = new List< int >(); list.Add(1); list.Add(2); foreach ( int value in list) { Console.WriteLine( "value is {0}" , value); } } } } |
C#的IL代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | . class private auto ansi beforefieldinit boxOrUnbox.Program extends [mscorlib]System.Object { // Methods .method private hidebysig static void Main ( string [] args ) cil managed { // Method begins at RVA 0x2050 // Code size 2 (0x2) .maxstack 8 .entrypoint IL_0000: nop IL_0001: ret } // end of method Program::Main .method private hidebysig static void Box () cil managed { // Method begins at RVA 0x2054 // Code size 10 (0xa) .maxstack 1 .locals init ( [0] object objValue ) IL_0000: nop IL_0001: ldc.i4.s 9 IL_0003: box [mscorlib]System.Int32 IL_0008: stloc.0 IL_0009: ret } // end of method Program::Box .method private hidebysig static void Unbox () cil managed { // Method begins at RVA 0x206c // Code size 16 (0x10) .maxstack 1 .locals init ( [0] object objValue, [1] int32 'value' ) IL_0000: nop IL_0001: ldc.i4.4 IL_0002: box [mscorlib]System.Int32 IL_0007: stloc.0 IL_0008: ldloc.0 IL_0009: unbox.any [mscorlib]System.Int32 IL_000e: stloc.1 IL_000f: ret } // end of method Program::Unbox .method private hidebysig static void LookatArrayList () cil managed { // Method begins at RVA 0x2088 // Code size 114 (0x72) .maxstack 2 .locals init ( [0] class [mscorlib]System.Collections.ArrayList 'array' , [1] int32 'value' , [2] class [mscorlib]System.Collections.IEnumerator CS$5$0000, [3] bool CS$4$0001, [4] class [mscorlib]System.IDisposable CS$0$0002 ) IL_0000: nop IL_0001: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor() IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: ldc.i4.1 IL_0009: box [mscorlib]System.Int32 IL_000e: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add( object ) IL_0013: pop IL_0014: ldloc.0 IL_0015: ldc.i4.2 IL_0016: box [mscorlib]System.Int32 IL_001b: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add( object ) IL_0020: pop IL_0021: nop IL_0022: ldloc.0 IL_0023: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.ArrayList::GetEnumerator() IL_0028: stloc.2 . try { IL_0029: br.s IL_004a // loop start (head: IL_004a) IL_002b: ldloc.2 IL_002c: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current() IL_0031: unbox.any [mscorlib]System.Int32 IL_0036: stloc.1 IL_0037: nop IL_0038: ldstr "value is {0}" IL_003d: ldloc.1 IL_003e: box [mscorlib]System.Int32 IL_0043: call void [mscorlib]System.Console::WriteLine( string , object ) IL_0048: nop IL_0049: nop IL_004a: ldloc.2 IL_004b: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() IL_0050: stloc.3 IL_0051: ldloc.3 IL_0052: brtrue.s IL_002b // end loop IL_0054: leave.s IL_0070 } // end .try finally { IL_0056: ldloc.2 IL_0057: isinst [mscorlib]System.IDisposable IL_005c: stloc.s CS$0$0002 IL_005e: ldloc.s CS$0$0002 IL_0060: ldnull IL_0061: ceq IL_0063: stloc.3 IL_0064: ldloc.3 IL_0065: brtrue.s IL_006f IL_0067: ldloc.s CS$0$0002 IL_0069: callvirt instance void [mscorlib]System.IDisposable::Dispose() IL_006e: nop IL_006f: endfinally } // end handler IL_0070: nop IL_0071: ret } // end of method Program::LookatArrayList .method private hidebysig static void LookatGenericList () cil managed { // Method begins at RVA 0x2118 // Code size 90 (0x5a) .maxstack 2 .locals init ( [0] class [mscorlib]System.Collections.Generic.List`1<int32> list, [1] int32 'value' , [2] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> CS$5$0000, [3] bool CS$4$0001 ) IL_0000: nop IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor() IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: ldc.i4.1 IL_0009: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0) IL_000e: nop IL_000f: ldloc.0 IL_0010: ldc.i4.2 IL_0011: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0) IL_0016: nop IL_0017: nop IL_0018: ldloc.0 IL_0019: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<int32>::GetEnumerator() IL_001e: stloc.2 . try { IL_001f: br.s IL_003c // loop start (head: IL_003c) IL_0021: ldloca.s CS$5$0000 IL_0023: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current() IL_0028: stloc.1 IL_0029: nop IL_002a: ldstr "value is {0}" IL_002f: ldloc.1 IL_0030: box [mscorlib]System.Int32 IL_0035: call void [mscorlib]System.Console::WriteLine( string , object ) IL_003a: nop IL_003b: nop IL_003c: ldloca.s CS$5$0000 IL_003e: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext() IL_0043: stloc.3 IL_0044: ldloc.3 IL_0045: brtrue.s IL_0021 // end loop IL_0047: leave.s IL_0058 } // end .try finally { IL_0049: ldloca.s CS$5$0000 IL_004b: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> IL_0051: callvirt instance void [mscorlib]System.IDisposable::Dispose() IL_0056: nop IL_0057: endfinally } // end handler IL_0058: nop IL_0059: ret } // end of method Program::LookatGenericList .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { // Method begins at RVA 0x2190 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ret } // end of method Program::.ctor } // end of class boxOrUnbox.Program |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架