C#装箱和拆箱

值类型和引用类型的基础知识

先举个例子,假如你现在在读一份报纸,为了给朋友一份,将报纸的全部内容复印了一份并交给他。他获得了一份属于自己的完整报纸。在这种情况下,我们处理的是值类型行为,所有的信息都掌握在自己手里,不需要从其他地方获取,你和朋友手中的是各自独立的,你在自己的报纸上添加注释,朋友的报纸上不会看见。

再假设你现在再看一个网页,与之前相比这次你给朋友的只是一个网页的Url,这种情况下,几时引用类型行为,Url代替了引用。为了能看到网页,需要在浏览器的输入Url来加载,假如网页由于某种原因需要改变,下次你个朋友打开的网页都会看到改变后的网页。

通过上面的例子应该会好理解一些,值类型和引用类型,两者之间本来没有多大的联系,设计人员通过一种名为装拆箱的操作,使得这两种类型创建了新的联系,让和任何 值类型都可以当成对象引用类型来操作。在C#中梳理了一下这两种类型

值类型:整型int;长整型long;浮点型float;字符型 char;布尔型bool;枚举 enum;结构 struct;他们统一继承ValueType

引用类型:数组,自定义类,委托,object,接口,字符串等;

装箱和拆箱

装箱:值类型转化为引用类型的过程。在堆上为新生成的引用对象分配内存,然后将值类型的数据拷贝到分配的内存中,返回堆中新分配对象的地址,这个地址就是指向对象的引用(如下图)

C#装箱和拆箱_第1张图片

拆箱:引用类型转化为值类型的过程。获取引用类型的地址,将用用对象的值拷贝到栈上的值类型实例中(注意 拆箱时可能会引发“转换无效”的异常。要记住,拆箱时强转的值类型,应以装箱时的值类型一致)

C#装箱和拆箱_第2张图片

装箱时 i是值类型的变量,o是引用类型的变量。将i的值赋给o有道理吗?o的值必须是一个引用,而数字10不是引用,它是一个整数值。实际发生的事情就是装箱:运行时将在堆上创建一个包含值(10)的对象(它是一个普通对象)。o的值是对该新对象的一个引用。该对象的值是原始值的一个副本,改变i的值不会改变箱内的值。

相反的操作—拆箱。必须告诉编译器将object拆箱成什么类型。如果使用了错误的类型(比如ob原先被装箱成unit或者long,或者根本就不是一个已装箱的值),就会抛出一个InvalidCastException异常。同样,拆箱也会复制箱内的值,在赋值之后,m和该对象之间不再有任何关系。

通过上述的原理可以看出,装拆箱分配内存和拷贝数据会影响性能的操作,尽量避免装拆箱。

你可能感兴趣的:(c#,c#,开发语言)