再谈C#的装箱和拆箱

上一篇写了一下装箱拆箱的定义和IL分析,这一篇我们看下使用泛型和不使用泛型引发装箱拆箱的情况

1. 使用非泛型集合时引发的装箱和拆箱操作 

看下面的一段代码:

1 var array = new ArrayList();
2 array.Add(1);
3 array.Add(2);
4  
5 foreach (int value in array)
6 {
7 Console.WriteLine(“value is {0}”,value);
8 }

代码声明了一个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#代码如下:

01 using System;
02 using System.Collections;
03 using System.Collections.Generic;
04  
05 namespace boxOrUnbox
06 {
07     class Program
08     {
09         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代码如下:

001 .class private auto ansi beforefieldinit boxOrUnbox.Program
002     extends [mscorlib]System.Object
003 {
004     // Methods
005     .method private hidebysig static
006         void Main (
007             string[] args
008         ) cil managed
009     {
010         // Method begins at RVA 0x2050
011         // Code size 2 (0x2)
012         .maxstack 8
013         .entrypoint
014  
015         IL_0000: nop
016         IL_0001: ret
017     // end of method Program::Main
018  
019     .method private hidebysig static
020         void Box () cil managed
021     {
022         // Method begins at RVA 0x2054
023         // Code size 10 (0xa)
024         .maxstack 1
025         .locals init (
026             [0] object objValue
027         )
028  
029         IL_0000: nop
030         IL_0001: ldc.i4.s 9
031         IL_0003: box [mscorlib]System.Int32
032         IL_0008: stloc.0
033         IL_0009: ret
034     // end of method Program::Box
035  
036     .method private hidebysig static
037         void Unbox () cil managed
038     {
039         // Method begins at RVA 0x206c
040         // Code size 16 (0x10)
041         .maxstack 1
042         .locals init (
043             [0] object objValue,
044             [1] int32 'value'
045         )
046  
047         IL_0000: nop
048         IL_0001: ldc.i4.4
049         IL_0002: box [mscorlib]System.Int32
050         IL_0007: stloc.0
051         IL_0008: ldloc.0
052         IL_0009: unbox.any [mscorlib]System.Int32
053         IL_000e: stloc.1
054         IL_000f: ret
055     // end of method Program::Unbox
056  
057     .method private hidebysig static
058         void LookatArrayList () cil managed
059     {
060         // Method begins at RVA 0x2088
061         // Code size 114 (0x72)
062         .maxstack 2
063         .locals init (
064             [0] class [mscorlib]System.Collections.ArrayList 'array',
065             [1] int32 'value',
066             [2] class [mscorlib]System.Collections.IEnumerator CS$5$0000,
067             [3] bool CS$4$0001,
068             [4] class [mscorlib]System.IDisposable CS$0$0002
069         )
070  
071         IL_0000: nop
072         IL_0001: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor()
073         IL_0006: stloc.0
074         IL_0007: ldloc.0
075         IL_0008: ldc.i4.1
076         IL_0009: box [mscorlib]System.Int32
077         IL_000e: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
078         IL_0013: pop
079         IL_0014: ldloc.0
080         IL_0015: ldc.i4.2
081         IL_0016: box [mscorlib]System.Int32
082         IL_001b: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
083         IL_0020: pop
084         IL_0021: nop
085         IL_0022: ldloc.0
086         IL_0023: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.ArrayList::GetEnumerator()
087         IL_0028: stloc.2
088         .try
089         {
090             IL_0029: br.s IL_004a
091             // loop start (head: IL_004a)
092                 IL_002b: ldloc.2
093                 IL_002c: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
094                 IL_0031: unbox.any [mscorlib]System.Int32
095                 IL_0036: stloc.1
096                 IL_0037: nop
097                 IL_0038: ldstr "value is {0}"
098                 IL_003d: ldloc.1
099                 IL_003e: box [mscorlib]System.Int32
100                 IL_0043: call void [mscorlib]System.Console::WriteLine(stringobject)
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(stringobject)
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

  


本文转载自 玉开的技术博客

详细的页面链接:http://www.cnblogs.com/yukaizhao/archive/2011/10/19/csharp_box_unbox_2.html

  

作者:Ivan
个人网站:http://www.IvanBy.com
原文地址:https://www.cnblogs.com/oneivan/p/2218208.html