.NET中的装箱和拆箱
在.NET中,装箱和拆箱是一组针对值类型转换成引用类型,引用类型转换为值类型的术语。
我们都知道在.NET中内存是分为堆栈和托管堆的,堆栈存放的是值类型的变量,托管堆中存储的是引用类型的对象。而装箱和拆箱是在两种类型之间发生转换的时候发生的。譬如如下代码
int x = 1;
Object o =x;
int x = 1;执行这句代码的时候x的值是分配在堆栈当中的。而Object我们都知道他是引用类型,这时CLR会对x进行装箱操作,将堆栈中的数据放置在托管堆中,由一个名为”o”的引用指向该对象。这个过程称为装箱,而拆箱是执行相反的操作。如int y = (int)o;可以看一下下面的一段程序。 ``\` class Program
{
static void Main(string[] args)
{
int x = 1;
object o = x;
int y = (int)o;
}
} \`\`\\\`
这段程序首先声明了一个值类型的x变量,然后转换成引用类型o,最后强制转换成值类型y。用IL Tools查阅一下编译好的IL语言。注:在IL语言中装箱的指令为box,拆箱的指令为unbox。
我们可以看到在IL_0004(对应object o=x)中计算机执行了一次装箱操作。而在IL_000b(对应int y =(int)o)中又执行了一次拆箱操作。装箱和拆箱是隐式的,是不用人工操作的,但这个也需要注意一点,就是性能问题。频繁装箱对计算机的性能影响很大,来做一个实验来看下面的代码。
class Program
{
static void Main(string[] args)
{
int count = 9999999;
WhithBox(count);
Other(count);
Console.ReadKey();
}
static void WhithBox(int count)
{
List
TimeControler.TimeControl.Start();
for (int i = 0; i < count; i++)
{
list.Add(i);
}
TimeControler.TimeControl.Stop();
Console.WriteLine(“装箱:” + TimeControler.TimeControl.GetMilliseconds());
}
static void Other(int count)
{
List
list = new List (); TimeControler.TimeControl.Start();
for (int i = 0; i < count; i++)
{
list.Add(i);
}
TimeControler.TimeControl.Stop();
Console.WriteLine(“非装箱:” + TimeControler.TimeControl.GetMilliseconds());
}
}
用一个List泛型来装载值类型的对象,第一个泛型采用object类型,第二个泛型采用int类型,为了验证第一个泛型是做装箱操作的,第二个泛型是不做装箱操作的。我们看一下这两个方法的IL语言。
在List
在List
差距还是挺大的5:1,至于为什么泛型集合也是引用对象却不会导致装箱操作,这个以后再研究。重要的是应该有意识的避免这种大量的装箱操作。