1.值类型与引用类型
C#的装箱与拆箱的本质应该就是值类型与引用类型之间的强转。在理解装箱跟拆箱之前先要理解一下什么是值类型,什么是引用类型。
这个课参考:C# 值类型与引用类型 - 简书
以C++进行类比,简单地将其理解的话那就是:值类型是不用new创建的对象,分配在栈;引用类型则是用new创建的对象(本质是一个指针),分配在堆。可参考:C++用new和不用new创建类对象区别_banbanlin的博客-CSDN博客_new 指针
2.拷贝运算符重载
为什么要关注运算符重载呢?因为要是C#能让重载拷贝构造函数和拷贝运算符,那么我们就可以自己去自定义封装值类型与引用类型了,而这显然是不被允许的。
可以参考哪些运算符能重载:C# 运算符重载 | 菜鸟教程
补充:在这可以在简单理解值类型隐含深拷贝,引用类型隐含浅拷贝。
3.简单的装箱拆箱理解
首先,最简单的拆箱装箱的理解:
void Test()
{
int i = 0;
object obj = i;//装箱,隐式强转。值类型转为引用类型
obj = 6;
print(i);//打印0
i=(int)obj;//拆箱相当于重新赋值。引用类型转为值类型
print(i);//打印6
}
将i赋值给obj,在赋值的过程中可以理解为调用了一个拷贝构造函数:
object obj = i;
等价于
object obj = new object(i);//在堆里开辟了一个新的空间
装箱由于重新开辟了一个空间,这个时候i与obj是相互独立的了,没有任何关系,无论obj怎么变i都不会变。所以这时候要让i也变的话需要将最后obj的值再强转为int赋值给i。
4.复杂一点的装箱拆箱理解
举例胜千言,举个struct类型进行拆装箱的例子直接说明。
interface ITest
{
void get();
void set(int i);
}
struct StructTest : ITest
{
private int i;
public void get()
{
Debug.Log(i);
}
public void set(int k)
{
i = k;
}
}
class ClassTest : ITest
{
int i;
public void get()
{
Debug.Log(i);
}
public void set(int k)
{
i = k;
}
}
void TestRefrenceType()
{
/*演示引用类型*/
ClassTest c = new ClassTest();
object o = c;//o与c绑定同一块空间
ClassTest c1 = c;//c1与c绑定同一块空间
((ClassTest)o).set(9);//((ClassTest) o)与c绑定的还是同一块空间
c1.get();//打印9
c.get();//打印9
}
void TestValueType()
{
/*演示值类型*/
StructTest s = new StructTest();
object o1 = s;//真的装箱了
((StructTest)o1).set(9);//真的拆箱了
s.get();//打印0
/*演示struct去实现接口类型*/
ITest i = new StructTest();//i是引用类型
object o2 = i;//o2和i指向一块空间,无装箱过程
((ITest)o2).set(9);//((ITest)o2)无拆箱过程
i.get();//打印9
}
在这里比较有趣的是用struct去实现接口,接口是值类型的。使用这种方法可以使得struct既能有值类型特性又能用引用类型的特性。