再谈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,

你可能感兴趣的:(C#)