文章来自微软官网: http://msdn.microsoft.com/zh-cn/library/yz2be5wk.aspx
装箱是将值类型转换为object类型或由此值类型实现的任何接口类型的过程。当CLR对值类型进行装箱时,会将该值包装到System.Object内部,再将后者存储在托管堆上。取消装箱将从对象中提取值类型。
装箱是隐式的;取消装箱是显示的。
装箱和取消装箱的概念是类型系统C#统一视图的基础,其中任一类型的值都被视为一个对象。
在下面的示例中,将整型变量i进行了装箱并分配给对象o。
int i = 123; object o = i; // 将i装箱
上述语句的结果是在堆栈上创建对象引用o,而在堆上则引用int类型的值。该值是赋给变量i的值类型的一个副本。下图说明了两个变量i和o之间的差异。
还可以像下面的示例一样执行显式装箱,但显式装箱从来不是必须的:
int i = 123; object o = (object) i; // 显式装箱
然后,可以将对象o取消装箱并分配给整型变量i:
o = 123; i = (int)o; // 取消装箱
取消装箱操作包括两个步骤:
1. 检查对象实例,以确保它是给定值类型的装箱值。
2. 将该值从实例复制到值类型变量中。
下面的语句演示装箱和取消装箱两种操作:
int i = 123; // 值类型 object o = i; // 装箱 int j = (int)o; // 取消装箱
下图演示上述语句的结果。
取消装箱转换
要在运行时成功取消装箱值类型,被取消装箱的项必须是对一个对象的引用,该对象是先前通过装箱该值类型的实例创建的。尝试取消装箱null会导致NullReferenceException。尝试取消装箱对不兼容值类型的引用会导致InvalidCastException。
以下示例演示如何在C#中使用装箱。
// String.Concat 示例. // String.Concat 函数有很多版本,下面这个版本的函数的3个参数 // 都必须为Object对象类型,所以 42 和 true 都将被装箱。 Console.WriteLine(String.Concat("Answer", 42, true));
装箱性能相关(以Unity中Debug.Log(object)函数为例)
考虑一种基本的装箱情况,当使用Debug.Log(object)函数时,函数的参数类型为object,也就意味着任何类型的变量都能传递给这个函数。例如当我们传递一个整数的时候,编译器将会对传递进来的整数进行装箱操作使其变成object类型,而我们知道装箱操作是需要耗费一点时间的,那么我们可以通过预见装箱操作来对其做一定的优化工作。如下面这个极端的例子所示:
// 编译器不需要每次调用Debug.Log函数的时候都执行装箱操作 void PrintingManyTimes(int n) { object obj = n; for (int i = 0; i < 500; i++) Debug.Log(obj); }