菜梗谈 - C#值类型与引用类型

菜梗谈 - C#值类型与引用类型

 

C#与C/C++的一个重要区别就是变量的存储形式。C/C++通过变量的定义方式决定变量的存储形式,例如:

假如你声明了一个class A

可以看出,C/C++因为指针的缘故,数据可以被指针间接地引用,而被间接引用的,可以是栈中的数据,也可以是堆中的数据,甚至,指针可以强制转换类型,这使得C/C++在拥有强大灵活性的同时,类型安全性变得非常薄弱。而C#,是一门非常强调类型安全的语言,对此,它的做法,就是将所有的类型分成两种形式:值类型和引用类型。

C#的值类型和引用类型的区别就是它们的存储形式:值类型存储在栈空间中,而引用类型存储在堆空间中。

从浅面上看,C#的值类型包括C/C++中的基本类型,比如int、long、float等,同时还包含struct;C#的引用类型就是class,还有string(string 比较特殊,先不谈它)。假定我们已经声明了一个struct Person,我们可以编写如下语句:
 
但如果Person定义了一个默认构造函数,且功能是对Person中的字段进行初始化,那么,下面的做法会更好,而且往往推荐那么做:

在这里,即使你使用了new,它还是被分配在栈空间中,new仅仅表示它会调用Person的构造函数。

但是,我们假定将以上Person定义成一个class,我们编写类似的语句:

所以在C#中,总是使用下面的写法实例化一个对象,而对象,也永远存储在堆空间中

所以说,C#是通过类型本身决定存储形式的。

其实,在C#中,int、long、float等基本类型都是struct,这是它们在C#中的别名,它们对应的全称是System.Int32、system.Int64、System.Float。所以,C#只有两种类型struct和class,它们都直接或间接地继承自system.Object。

string也属于class,也就是说它的数据是分配在堆空间中的,但是它在使用方式上却更像值类型,如:

由于.Net Framework的一些底层处理,str1和str2并不同时指向一个实例,而是分别指向不同的实例,对str2的改写是不会影响到str1的(其实,当你改写str2的时候并不是改写原有的实例,而是分配了一个新实例,而原来的实例因为不再有引用将会被GC回收)。

C#的值类型和引用类型有了非常明确的界限,但是,我们有时却要将值类型转换成引用类型或是将引用类型转换成指类型,这种情况非常之多,例如,你要将int类型变量存储到集合类中,或是从集合类中取出数据给int变量,这就涉及到boxing(装箱)和unboxing(拆箱),C#中的装箱和拆箱,就是为这种目的而设计。它们的工作方式其实很容易理解,所谓装箱,就是将值类型做一份拷贝,而这份拷贝,被放入堆空间中,如:

i的数据被拷贝一份放入了堆空间,并且由j引用,因为值类型也是继承自object,所以,是完全可行的。这就是装箱的操作,而拆箱,采用一下方式:

拆箱是装箱的反操作,它将装箱到堆中的数据重新放入栈中。


---------
菜梗谈 - 甜菜的读书笔记
---------
Sep 15.2010

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值