• C#中值类型和引用类型


    本文将介绍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(5,9);
    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#中的值类型和引用类型,以及栈和堆的基本概念。然后分析了值类型和引用类型在栈和堆中的存放。

    同时,我们也了解到了:

    • 当使用引用类型时,我们是在和指向引用类型的引用(指针)打交道,而不是引用类型本身
    • 当使用值类型时,我们是在和值类型本身打交道
  • 相关阅读:
    mysql分页查询语法
    不同浏览器CSS样式不兼容问题
    js引入jquery问题
    ElasticSearcher的安装以及安装过程中出现的问题
    Mybites逆向工程的搭建
    Maven遇到的各种问题
    Maven安装和配置
    Maven报错:Unsupported major.minor version 51.0
    teamviewer远程是账号密码都没错但是报正在初始化参数...
    远程服务器时无密码登录
  • 原文地址:https://www.cnblogs.com/wilber2013/p/4286981.html
Copyright © 2020-2023  润新知