装箱(boxing)和拆箱(unboxing)是C#类型系统的核心概念。
值类型继承至System.ValueType,引用类型继承至System.Object,详细的类继承关系如下图所示:
在托管堆上分配一个新的对象。
将栈上的数据转移到托管堆新创建的对象空间上。
1 int n = 100; 2 //有没有发生装箱?没有,只是调用方法.查看IL没有box,unbox关键字 3 string s = Convert.ToString(n); 4 int m = int.Parse(s); 5 Console.ReadKey();
装拆箱:
1 int n = 100; 2 object o = n;//发生了一次装箱 3 int m = (int)o; //发生了一次拆箱 4 Console.WriteLine(m); 5 Console.ReadKey();
查看IL代码如下:
注意问题:装箱的时候是什么类型,拆箱的时候也必须使用对应的类型拆箱。否则会报错
=============================================================================================
之前写了一篇比较是否为同一对象(比较是否为同一对象),object.ReferenceEquals如果两个参数都是值类型会是怎样的呢?
1 int n = 100; 2 int m = 100; 3 Console.WriteLine(n.Equals(m)); 4 Console.WriteLine(object.ReferenceEquals(n, m)); 5 Console.ReadKey();
运行结果是false,我们来查看下IL代码,很明显,n和m都装箱变为了引用类型,它们所指向的地址不一样,无论如何都是不成立的
=================================================================================
拼接字符串也会涉及装箱问题:比如:
1 int n = 10; 2 object o = n; //装箱一次 3 n = 100; 4 Console.WriteLine(n + "," + (int)o); //装箱两次,拆箱一次 5 Console.ReadKey();
还是得查看一下IL代码:因为拼接字符串是调用string.Concat(object,object,object)这个方法,每拼接一个字符串会把int隐式装箱再连接
======================================================================
装箱和拆箱性能问题
使用ArrayList:
1 ArrayList arrInt = new ArrayList(); 2 Stopwatch watch = new Stopwatch(); 3 watch.Start(); 4 for (int i = 0; i < 1000000; i++) 5 { 6 arrInt.Add(i); 7 } 8 watch.Stop(); 9 Console.WriteLine(watch.Elapsed); 10 Console.ReadKey();
运行结果:
使用泛型:
1 //使用泛型集合避免装箱和拆箱。 2 List<int> arrInt = new List<int>(); 3 Stopwatch watch = new Stopwatch(); 4 watch.Start(); 5 for (int i = 0; i < 1000000; i++) 6 { 7 arrInt.Add(i); 8 } 9 watch.Stop(); 10 Console.WriteLine(watch.Elapsed); 11 Console.ReadKey();
运行结果:
这可以看出装拆箱还是比较影响性能的