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

 更新时间:2017年09月30日 09:50:24   作者:Amedeo  
这篇文章主要为大家详细介绍了C#中值类型和引用类型的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

在C#中,值类型和引用类型是相当重要的两个概念,必须在设计类型的时候就决定类型实例的行为。如果在编写代码时不能理解引用类型和值类型的区别,那么将会给代码带来不必要的异常。很多人就是因为没有弄清楚这两个概念从而在编程过程中遇到了很多问题,在这里博主浅谈对值类型和引用类型的认识。

首先从概念上看,值类型直接存储其值,而引用类型存储对其值的引用。从而这两种类型存储在内存的不同地方。

其次从内存空间上看,值类型是在栈中操作,而引用类型则在堆中分配存储单元。

栈在编译的时候就分配好内存空间,在代码中有栈的明确定义,而堆是程序运行中动态分配的内存空间,可以根据程序的运行情况动态地分配内存的大小。因此,值类型总是在内存中占用一个预定义的字节数。而引用类型的变量则在栈中分配一个内存空间,这个内存空间包含的是对另一个内存位置的引用,这个位置是托管堆中的一个地址,即存放此变量实际值的地方。

也就是说值类型相当于现金,要用就直接用,而引类型相当于存折,要用得先去银行取。

但值类型在栈上分配内存,而引用类型在托管堆上分配内存,只是一种笼统的说法。下面对其进行详细描述。

(1)对于值类型的实例,如果作为方法中的局部变量,则被创建在线程栈上;如果该实例作为类型的成员,则作为类型成员的一部分,连同其他类型字段存放在托管堆上。

每种值类型均有一个隐式的默认构造函数来初始化该类型的默认值。例如:

int i = new int(); 

等价于:

Int32 i = new Int32(); 

等价于:

int i = 0; 

等价于:

Int32 i = 0; 

使用new运算符时,将调用特定类型的默认构造函数并对变量赋以默认值。在上例中,默认构造函数将值0赋给了i。

说明:C#的所有值类型均隐式派生自System.ValueType,而System.ValueType直接派生于System.Object。即System.ValueType本身是一个类类型,而不是值类型。其关键在于ValueType重写了Equals方法,从而对值类型按照实例的值来比较,而不是引用地址来比较。

(2)引用类型的实例创建在托管堆上。

下面以一段代码来详细讲解一下值类型与引用类型的区别

namespace Test 
  { 
      class Program 
      { 
        static void Main(string[] args) 
        { 
       //调用ReferenceAndValue类中的Demonstration方法 
          ReferenceAndValue.Demonstration(); 
          Console.ReadLine(); 
        } 
      } 
      public class stamp       //定义一个类 
      { 
        public string Name { get; set; }    //定义引用类型 
        public int Age { get; set; }    //定义值类型 
      } 
      public static class ReferenceAndValue   //定义一个静态类 
      { 
        public static void Demonstration()   //定义一个静态方法 
        { 
          stamp Stamp_1 = new stamp { Name = "Premiere", Age = 25 }; //实例化 
          stamp Stamp_2 = new stamp { Name = "Again", Age = 47 }; //实例化 
          int age = Stamp_1.Age;     //获取值类型Age的值 
          Stamp_1.Age = 22;     //修改值类型的值 
          stamp guru = Stamp_2;     //获取Stamp_2中的值 
          Stamp_2.Name = "Again Amend";   //修改引用的Name值 
          Console.WriteLine("Stamp_1's age:{0}", Stamp_1.Age); //显示Stamp_1中的Age值 
          Console.WriteLine("age's value:{0}", age); //显示age值 
          Console.WriteLine("Stamp_2's name:{0}", Stamp_2.Name); //显示Stamp_2中的Name值 
          Console.WriteLine("guru's name:{0}", guru.Name); //显示guru中的Name值 
        } 
    } 
  }

通过运行上面一段程序之后我们可以看出,当改变了Stamp_1.Age的值时,age并没有跟着变,但在改变了anders.Name的值后,guru.Name却跟着变了,这就是值类型和引用类型的区别。在声明age值类型变量时,将 Stamp_1.Age的值赋给它,这时,编译器在栈上分配了一块空间,然后把Stamp_1.Age的值填进去,二者没有任何关联,就像在计算机中复制文件一样,只是把Stamp_1.Age的值拷贝给age了。而引用类型则不同,在声明guru时把Stamp_2赋给它,前面说过,引用类型包含的只是堆上数据区域地址的引用,其实就是把Stamp_2的引用也赋给guru,因此它们指向了同一块内存区域。既然是指向同一块区域,不管修改谁,另一个的值都会跟着改变,就像信用卡跟亲情卡一样,用亲情卡取了钱,与之关联的信用卡账上也会跟着发生变化。

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

相关文章

  • UGUI绘制多点连续的平滑曲线

    UGUI绘制多点连续的平滑曲线

    这篇文章主要为大家详细介绍了UGUI绘制多点连续的平滑曲线,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-12-12
  • C# FTP操作类分享

    C# FTP操作类分享

    这篇文章主要为大家分享了C# FTP操作类的相关代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-06-06
  • C# 任务的异常和延续处理

    C# 任务的异常和延续处理

    本文主要介绍了C# 任务的异常和延续处理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-12-12
  • C#开发答题赢钱游戏(自动答题器)

    C#开发答题赢钱游戏(自动答题器)

    现在最火的直播游戏,那就是答题赢钱直播了,如百万英雄、芝士超人、花椒直播、冲顶大会等等,这些游戏的玩法都很简单,答对12题即可瓜分奖金了。玩法虽简单但是完全答对12题难度就挺高了,下面小编给大家带来了C#开发答题赢钱游戏,需要的朋友参考下吧
    2018-01-01
  • C# SDK实现百度云OCR的文字识别功能

    C# SDK实现百度云OCR的文字识别功能

    这篇文章主要为大家详细介绍了C# SDK实现百度云OCR的文字识别功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-11-11
  • 小菜编程成长记(一 面试受挫——代码无错就是好?)

    小菜编程成长记(一 面试受挫——代码无错就是好?)

    小菜编程成长记(一 面试受挫——代码无错就是好?)...
    2006-10-10
  • .Net常见问题之C#中的委托

    .Net常见问题之C#中的委托

    这篇文章主要介绍了.Net常见问题委托概念的介绍,委托类似于C++中的函数指针,但是又有所不同,下面就针对委托这个概念给大家详细介绍下,需要的朋友可以参考下
    2015-07-07
  • Unity Shader实现黑幕过场效果

    Unity Shader实现黑幕过场效果

    这篇文章主要为大家详细介绍了Unity Shader实现黑幕过场效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • C#截图程序类似腾讯QQ截图实现代码

    C#截图程序类似腾讯QQ截图实现代码

    拖动过程中显示当前鼠标下一小块的图像信息 尺寸、颜色信息的 注意 这里颜色是用的ARGB,需要的朋友可以参考下
    2012-12-12
  • C# 拼图魔方小游戏

    C# 拼图魔方小游戏

    这篇文章主要介绍了C# 拼图魔方小游戏,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-02-02

最新评论