C#中值类型和引用类型的区别

一、值类型和引用类型的区别

.NET的类型可以分为两类:值类型和引用类型。这两种类型各有特点,即使它们都继承自System.Object,并且有装箱和拆箱等操作确保两种类型可以方便地交互,但是理解值类型和引用类型将有助于程序员编写出高效的代码,相反的,在不理解值类型和引用类型的情况下,程序员很容易编写出可以正确执行但性能较差的代码。

所有.NET的类型都可以分为两类:值类型和引用类型。最简单也最明确的一个区分标准是:所有的值类型都继承自System.ValueType(System.ValueType继承自System.Object),也就是说,所有继承自System.ValueType的类型都是值类型,而其他类型都是引用类型。常用的值类型包括结构、枚举、整数型、浮点型、布尔型等,而在C#中所有以class关键字定义的类型都是引用类型。

1、赋值时的区别

引用类型和值类型最显著的一个区别在于变量的赋值问题。值类型的变量将直接获得一个真实的数据副本,而对引用类型的赋值仅仅是把对象的引用赋给变量,这样就可能导致多个变量引用到一个实际对象实例上。

来看下面一个简单的示例:首先为了测试建立一个简单的引用类型和一个简单的值类型。然后在Main方法中,测试对值类型和引用类型对象进行赋值的不同结果,代码如下:

using System;

namespace ConsoleApp1
{
    /// <summary>
    /// 一个简单的引用类型
    /// </summary>
    public class Ref
    {
        public int iValue { get; set; }

        public Ref(int i)
        {
            iValue = i;
        }

        public override string ToString()
        {
            return $"iValue的值为:{iValue.ToString()}";
        }
    }

    /// <summary>
    /// 一个简单的值类型
    /// </summary>
    public struct Val
    {
        public int Value { get; set; }

        public Val(int i)
        {
            Value = i;
        }

        public override string ToString()
        {
            return $"Value的值为:{Value.ToString()}";
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            // 测试引用类型的赋值
            Ref ref1 = new Ref(1);
            Ref ref2 = ref1;
            // 赋值
            ref2.iValue = 2;

            // 测试值类型的赋值
            Val val1 = new Val(1);
            Val val2 = val1;
            val2.Value = 2;
            //输出
            Console.WriteLine($"ref1:{ref1}");
            Console.WriteLine($"ref2:{ref2}");
            Console.WriteLine($"val1:{val1}");
            Console.WriteLine($"val2:{val2}");
            Console.ReadKey();
        }
    }
}

简单分析上面的代码,程序定义了一个引用类型Ref和一个值类型Val,两者的内容几乎完全相同。在Main方法中,分别测试了引用类型和值类型的赋值。当代码把一个引用类型变量赋值给另一个引用变量:Ref ref2 = ref1时,实际上是把ref1的对象引用赋给了ref2,这样,两个引用变量实际指向了同一个对象。如图所示:

而值类型的赋值则不同,val1和val2都保留了属于自己的数据副本,所以当val2改变时,val1不受到影响。如图所示:

上面代码的输出结果:

2、内存分配的区别

除了赋值的区别,引用类型和值类型在内存的分配位置上也有区别。引用类型的对象将会在堆上分配内存,而值类型的对象则会在堆栈上分配内存。堆栈的空间相对有限,但运行效率却比高的多。

3、来自继承结构的区别

最后,由于所有的值类型都有一个共同的基类:System.ValueType,所以值类型拥有一些引用类型不具有的共同性质,较重要的一点是值类型的比较方法:Equals方法的实现有了改变。所有的值类型都实现了内容的比较,而引用类型在没有重写Equals方法的情况下,仍然采用引用比较。还是以上面的代码为了,看下面的代码:

using System;

namespace ConsoleApp1
{
    /// <summary>
    /// 一个简单的引用类型
    /// </summary>
    public class Ref
    {
        public int iValue { get; set; }

        public Ref(int i)
        {
            iValue = i;
        }

        public override string ToString()
        {
            return $"iValue的值为:{iValue.ToString()}";
        }
    }

    /// <summary>
    /// 一个简单的值类型
    /// </summary>
    public struct Val
    {
        public int Value { get; set; }

        public Val(int i)
        {
            Value = i;
        }

        public override string ToString()
        {
            return $"Value的值为:{Value.ToString()}";
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            //// 测试引用类型的赋值
            //Ref ref1 = new Ref(1);
            //Ref ref2 = ref1;
            //// 赋值
            //ref2.iValue = 2;

            //// 测试值类型的赋值
            //Val val1 = new Val(1);
            //Val val2 = val1;
            //val2.Value = 2;

            //输出
            //Console.WriteLine($"ref1:{ref1}");
            //Console.WriteLine($"ref2:{ref2}");
            //Console.WriteLine($"val1:{val1}");
            //Console.WriteLine($"val2:{val2}");

            // 测试引用类型的赋值
            Ref ref1 = new Ref(1);
            Ref ref2 = new Ref(1);

            // 测试值类型的赋值
            Val val1 = new Val(1);
            Val val2 = new Val(1);

            Console.WriteLine(ref1.Equals(ref2));
            Console.WriteLine(val1.Equals(val2));
            Console.ReadKey();
        }
    }
}

程序输出结果:

在Main方法中,分别定义了一对内容完全相同的值类型对象和引用类型对象,调用Equals方法来比较,发现值类型对象比较返回true,而引用类型对象比较返回false。

二、总结

所有继承自System.ValueType的类型都是值类型,而其他类型都是引用类型。值类型的赋值会产生一个新的数据副本,所以每个值类型都拥有一个数据副本。而引用类型的赋值则是赋值引用。值类型的对象分配在堆栈上,而引用类型的对象分配在堆上。当比较两个值类型时,进行的是内容比较。而比较两个引用类型时,进行的是引用比较。

上面列举的仅仅是值类型和引用类型的一些主要区别,通过这些本质区别,可以产生更多的细节区别,有兴趣的话可以自行研究。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • C#基础入门之值类型和引用类型的区别详析

    目录 一.值类型和引用类型的区别 1.赋值时的区别 2.内存分配的区别 3.来自继承结构的区别 二.总结 一.值类型和引用类型的区别 .NET的类型可以分为两类:值类型和引用类型.这两种类型各有特点,即使它们都继承自System.Object,并且有装箱和拆箱等操作确保两种类型可以方便地交互,但是理解值类型和引用类型将有助于程序员编写出高效的代码,相反的,在不理解值类型和引用类型的情况下,程序员很容易编写出可以正确执行但性能较差的代码. 所有.NET的类型都可以分为两类:值类型和引用类型.最简单

  • c#值类型和引用类型使用示例

    在刚参加工作面试时,我们经常会遇到有关值类型和引用类型的问题,你回答的怎么样直接影响你在别人心目中的印象,你回答的不好说明你对C#没有深入的了解学习,今天我带大家回顾下C#中的引用类型和值类型.CLR支持两种类型:引用类型和值类型.虽然FCL中大多数类型都是引用类型但程序中用的最多的还是值类型.引用类型总是从托管堆上分配的,C#的new操作会返回对象的内存地址--也就是指向对象的数据的内存地址.设想假设每次使用一个Int32值时,都进行一次内存分配,性能会受到多大的影响,为了提升简单.常用的类型

  • C#值类型和引用类型的深入理解

    从概念上看,值类型直接存储其值,而引用类型存储对其值的引用.这两种类型存储在内存的不同地方.在C#中,我们必须在设计类型的时候就决定类型实例的行为.这种决定非常重要,用<CLR via C#>作者Jeffrey Richter的话来 说,"不理解引用类型和值类型区别的程序员将会给代码引入诡异的bug和性能问题(I believe that a developer who misunderstands the difference between reference types and

  • 浅谈C#中的值类型和引用类型

    一.基本概念 C#只有两种数据类型:值类型和引用类型 值类型在线程栈分配空间,引用类型在托管堆分配空间 值类型转为引用类型称成为装箱,引用类型转为值类型称为拆箱 以下是值类型和引用类型对照表 从上图可以简单看出:string,Object,数组,class是引用类型,简单类型,枚举,结构是值类型. 二.代码展示 定义一个类和结构调用赋值 内存分配情况如下图: 从这张图可以看出,class实例化出来的对象,指向了内存堆中分配的空间:truct实例化出来的对象,是在内存栈中分配. 修改代码如下: 内

  • C#中值类型和引用类型的区别深度分析

    本文通俗易懂的分析了C#中值类型和引用类型的区别.分享给大家供大家参考.具体分析如下: 似乎"值类型和引用类型的区别"是今年面试的流行趋势,我已然是连续三次(目前总共也就三次)面试第一个问题就遇到这个了,这是多大的概率啊,100%,哈哈,我该买彩票去! 言归正传,咱还是先来探讨探讨这二者之间有什么区别吧.记得有一次电话面试中,我直接跟面试官说:"值类型是现金,引用类型是存折",后来想想当时说这话虽是有点儿冲动地脱口而出,但也没什么不妥.我这人不善于背理论的教条,喜欢

  • c#基础系列之值类型和引用类型的深入理解

    前言 不知不觉已经踏入坑已10余年之多,对于c#多多少少有一点自己的认识,写出来渴求同类抨击,对自己也算是个十年之痒的一个总结. C#把数据类型分为值类型和引用类型 1.1:从概念上来看,其区别是值类型直接存储值,而引用类型存储对值的引用. 1.2:这两种类型在内存的不同地方,值类型存储在堆栈中,而引用类型存储在托管对上.存储位置的不同会有不同的影响. 下面话不多说了,来一起看看详细的介绍吧 基本概念 CLR支持两种类型:值类型和引用类型. 面试过很多5年左右的同学,有很多连值类型和引用类型的基

  • c#字符串值类型与引用类型比较示例

    复制代码 代码如下: classProgram{    staticvoid Main() {        int a = 9;    //给变量a赋值为9        int b = a;   //将a的副本给变量b        b = 10;        Console.WriteLine(string.Format("a={0},b={1}", a, b));        Person ZS = newPerson();       //张三        ZS.Age

  • 浅析C# 中的类型系统(值类型和引用类型)

    今天要写的东西都是书中一些概念性的东西,就当抄笔记,以提问对话的方式将其写出来吧,说不定以后面试能有点谈资~~~ Q1.C#1系统类型包含哪三点特性? A1.C#1类型系统是静态的.显式的和安全的. Q2.为什么称为静态类型? A2.静态类型是用来描述表达式在编译时的类型,当声明一个类型的变量时,不能将变量指向其它类型的对象. Q3.显式类型和隐式类型的区别? A3.显式类型和隐式类型只有静态类型中的语言才有意义.显式类型需要显式声明一个变量的类型,而隐式类型则将类型的判断责任推给编译器,但是在

  • c# 引用类型和值类型

    CLR支持两种类型:引用类型和值类型. 引用类型总是从托管堆上分配的. c#中的New操作符返回对象的内存地址. 引用对象的注意点: 1.内存从托管堆中分配 2.堆上分配对象,有一些额外的操作,影响一些性能的 3.从托管堆中分配一个对象时,可能强制执行一次垃圾回收. CLR中的值类型是轻量级的.不需要提领一个指针,不需要垃圾回收,可以减少垃圾回收的次数. 在CLR中一般称为"类"的都是引用类型,所有的值类型都称为结构或者枚举. 所有的结构都是抽象类ValueType的直接派生类.Val

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

    在C#中,值类型和引用类型是相当重要的两个概念,必须在设计类型的时候就决定类型实例的行为.如果在编写代码时不能理解引用类型和值类型的区别,那么将会给代码带来不必要的异常.很多人就是因为没有弄清楚这两个概念从而在编程过程中遇到了很多问题,在这里博主浅谈对值类型和引用类型的认识. 首先从概念上看,值类型直接存储其值,而引用类型存储对其值的引用.从而这两种类型存储在内存的不同地方. 其次从内存空间上看,值类型是在栈中操作,而引用类型则在堆中分配存储单元. 栈在编译的时候就分配好内存空间,在代码中有栈的

  • c#中值类型和引用类型的基础教程

    前言 值类型和引用类型,是c#比较基础,也必须掌握的知识点,但是也不是那么轻易就能掌握,今天跟着老胡一起来看看吧. 典型类型 首先我们看看这两种不同的类型有哪些比较典型的代表. 典型值类型 int, long, float, double等原始类型中表示数字的类型都是值类型,表示时间的datatime也是值类型,除此之外我们还可以通过关键字struct自定义值类型. 典型引用类型 原始类型中,array, list, dictionary, queue, stack和string都是引用类型,除

  • c# 引用类型与值类型的区别详解

    解析:CLR支持两种类型:值类型和引用类型.用Jeffrey Richter(<CLR via C#>作者)的话来说,"不理解引用类型和值类型区别的程序员将会把代码引入诡异的陷阱和诸多性能问题".这就要求我们正确理解和使用值类型和引用类型.值类型包括C#的基本类型(用关键字int.char.float等来声明),结构(用struct关键字声明的类型),枚举(用enum关键字声明的类型):而引用类型包括类(用class关键字声明的类型)和委托(用delegate关键字声明的特

随机推荐