本文将介绍C#类型系统中的值类型和引用类型,以及两者之间的一些区别。同时,还会介绍一下装箱和拆箱操作。

值类型和引用类型

首先,我们看看在C#中哪些类型是值类型,哪些类型是引用类型。

值类型:

  • 基础数据类型(string类型除外):包括整型、浮点型、十进制型、布尔型。  
    • 整型(sbyte、byte、char、short、ushort、int、uint、long、ulong )
    • 浮点型(float 和 double )
    • 十进制型(decimal )
    • 布尔型(bool )
  • 结构类型(struct)
  • 枚举类型(enum)

引用类型:

  • class、interface、delegate、object、string、Array

默认值

变量的初始化中,都会有一个默认值,在C#中,我们可以通过default关键字去查看某个类型的默认值。

通过default(int)可以看到,int的默认值是0,default(bool)显示布尔类型的默认值是false。

对于所有的引用类型,默认值都会是null。

注意,这里有个特殊的情况就是结构struct,如果对一个结构进行default操作,我们将得到每个结构成员的初始值状态。也就是说,值类型成员赋予值类型的默认值,引用类型成员赋予引用类型的默认值。

简单对比值类型和引用类型

下面,我们通过一个简单的例子看看。假设有一个Point类型,有x和y两个坐标成员。

同样是下面一段代码

Point p1 = new Point(,);
Point p2 = p1;

如果Point类型是通过结构struct实现,那么p2将会是p1的一个副本,也就是说任何一个的修改都不会影响另外一个;如果Point类型是通过类class实现,那么p2和p1的引用值将会指向同一个对象。

为了进一步了解值类型和引用类型,我们需要介绍一下栈和堆这两个基本概念。

栈和堆

当我们在32位系统上运行一个程序的时候,这个程序就会有一个4GB的进程运行空间。我们所要讨论的栈和堆就存放在这个4GB的空间中。

栈和堆的简介

在C#中,栈(Stack)是指调用栈(call stack);堆(Heap)是指托管堆,由.NET垃圾收集器自动管理。

这里就不对栈和堆进行详细的分析了,只是举一个简单的例子来大致描述栈和堆的工作原理。

从图中可以看到,局部变量在栈上的变化(入栈),当函数执行结束后,栈上的空间将会被清理;但是我们在堆上分配的空间始终从在,只能等待GC去帮我们清理不会被引用到的空间。

值类型和引用类型的存放

介绍过栈和堆之后,下面我们看看值类型和引用类型是怎么存放的。

对于值类型的变量,这个变量本身就代表这个值类型的值;但是,对于引用类型的变量,这个引用类型的实例是在托管堆上分配的空间,而这个变量本身只是代表一个指向托管堆实例的引用(指针)

所以这里,我们可以对值类型和引用类型变量的存储有两个概括:

  • 引用类型永远存储在堆里
  • 值类型和引用(指针)永远存储在它们声明时所在的堆或栈里
    • 如果一个值类型不是在方法中定义的,而是在一个引用类型里,那么此值类型将会被放在这个引用类型里并存储在堆上

注意:根据上面第二点概括,可以得到"值类型一定存储在栈中"这个说法是错误的。例如,我们有一个Student类,在这个类中的Age属性是一个值类型,但是这个值类型是存储在Student类实例的空间中,也就是在堆上。

class Student
{
public string Name { get; set; }
public int Age{ get; set; }

装箱和拆箱

由于C#中所有的数据类型都是由基类System.Object继承而来的,所以值类型和引用类型的值可以通过显式(或隐式)操作相互转换。

这里,可以将装箱和拆箱描述为:

  • 装箱是将值类型转换为引用类型
  • 拆箱是将引用类型转换为值类型

装箱/拆箱的内部操作

其实,在装箱和拆箱的过程中都对应一系列的转换,这里就通过下图表示了。

在值类型进行装箱时,生成的是全新的引用对象,这会有时间损耗,也就是造成效率降低。所以在C# 2.0中就引入了泛型来减少装箱操作和拆箱操作消耗。

总结

本文介绍了C#中的值类型和引用类型,以及栈和堆的基本概念。然后分析了值类型和引用类型在栈和堆中的存放。

同时,我们也了解到了:

  • 当使用引用类型时,我们是在和指向引用类型的引用(指针)打交道,而不是引用类型本身
  • 当使用值类型时,我们是在和值类型本身打交道

C#中值类型和引用类型的更多相关文章

  1. JavaScript中值类型和引用类型的区别

    JavaScript的数据类型分为两类:原始类型和对象类型.其中,原始类型包括:数字.字符串和布尔值.此外,JavaScript中还有两个特殊的原始值:null和undefined,它们既不是数字也不 ...

  2. JAVA中值类型和引用类型的不同(面试常考)

    转载:https://www.cnblogs.com/1ming/p/5227944.html 1. JAVA中值类型和引用类型的不同? [定义] 引用类型表示你操作的数据是同一个,也就是说当你传一个 ...

  3. C#中值类型和引用类型的差别浅记

    C#中值类型和引用类型的差别浅记         在C#中,变量的类型分为两种.各自是值类型和引用类型.         值类型的变量直接存储值,说得更详细一些,就是值类型变量在内存中直接存储它们自身 ...

  4. C#中值类型和引用类型图解

    举几个值类型和引用类型的内存配置: 值类型存储在栈中,引用类型堆里: 1,数组 数组是引用类型,但是数组的元素可以是值类型或引用类型 2. 结构 结构是值类型,简略的看个例子 struct sampl ...

  5. java中值类型和引用类型的区别

    [定义] 引用类型表示你操作的数据是同一个,也就是说当你传一个参数给另一个方法时,你在另一个方法中改变这个变量的值,那么调用这个方法是传入的变量的值也将改变. 值类型表示复制一个当前变量传给方法,当你 ...

  6. JavaScript中值类型与引用类型

    JavaScript中的变量类型有哪些? 值类型:字符串(string).数值(number).布尔值(boolean).null.undefined 引用类型:对象(Object).数组(Array ...

  7. .net中值类型、引用类型理解的c#代码示例

    下面是以前在公司的时候给别人讲解值类型.引用类型时创建的c#代码示例,从实际使用时的角度出发,对于初学者还是很有帮助的.这里并没有深入讲解值类型包含引用类型成员时(如struct)在内存中的存放情况等 ...

  8. JS中值类型和引用类型

    一.值类型 例子: var a=10; var b=a; a=20; console.log(b); 例子中,将a的值赋给了b,b=10,然后改变a的值不会影响b的值,a和b是独立的两份,互不影响. ...

  9. C#中值类型与引用类型通俗理解

    关于值类型和引用类型已经有很多人写了很多文章,但是很多人也只是停留在字面上的理解,如果采用一种通俗的方法来解释,想必很多人都会理解.我们都知道值类型存储在栈上,引用类型存储在堆上,引用类型都是xxx类 ...

随机推荐

  1. chrome45以后的版本安装lodop后,仍提示未安装解决

    请先查看你chrome浏览器的版本,如果是45版本以前的版本,安装后仍提示 "未安装" 或 "请升级" 请参照本链接解决:http://blog.sina.co ...

  2. hdu 敌兵布阵(线段树之单点更新)

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  3. 限制input输入类型(多种方法实现)

    1.只能输入和粘贴汉字 <input onkeyup="value=value.replace(/[^\u4E00-\u9FA5]/g,'')" onbeforepaste= ...

  4. 标准C IO函数和 内核IO函数 效率(时间)比较

    前言 标准C提供的文件相关的IO函数,除标准错误输出是不带缓冲的(可以尽快的将错误消息显示出来)之外,所有与终端相关的都是行缓冲,其余都是全缓冲的. 我们可以使用setbuf,setvbuf改变指定流 ...

  5. spark Basic code demo

    spark-shell --master=spark://namenode01:7077 --executor-memory 2g --driver-class-path /app/spark141/ ...

  6. 读《深入理解Java虚拟机》有感——第一部分:Class文件的结构

    1.产生 源码(.java文件)——>编译器(如:javac)——>字节码(.class文件)——>虚拟机(如:HotSpot)执行 2.Class文件  1)构成:         ...

  7. JS高程读书笔记-第一、二章-内附在线思维导图和quizlet卡片

    之前在kindle上买了高程,今天又到了纸质的<JavaScript语言精粹>,<高性能JavaScript>,<JavaScipt设计模式>,开始读书之旅啦. 我 ...

  8. HDU 4267 A Simple Problem with Integers --树状数组

    题意:给一个序列,操作1:给区间[a,b]中(i-a)%k==0的位置 i 的值都加上val  操作2:查询 i 位置的值 解法:树状数组记录更新值. 由 (i-a)%k == 0 得知 i%k == ...

  9. Tsung测试openfire服务器

    环境准备 安装Tsung.安装openfire.安装Spark Tsung使用 要对openfire进行压力测试,因此我们主要讲解如何利用jabber_register.xml在openfire上面注 ...

  10. 使用 ssh 连接github的方法说明(gitub的官方说法)

    https://help.github.com/articles/generating-an-ssh-key/