C#值类型与引用类型的学习

目录

1.前言

2.概念

值类型

引用类型

string的探索

3.通用系统类型(CTS)

4.值类型和引用类型在内存中的部署

栈和堆的了解

值类型和引用类型在栈和堆中的分配

5.值类型与引用类型适用场合

参考


1.前言

学习C#也快两年了,之前接触过C,C++,都不深入,但是知道基础,所以在C#学习并没有在基础上用过多时间,后来跟项目,遇到问题,现学现卖,快要找工作了,觉得基础的东西还是得再学习下,今天就先看看C#值类型和引用类型的区别。

2.概念

c#中有两种基本类型,它们分别是值类型和引用类型

值类型

变量直接存储在内存中,byte,short,int,long,float,double,decimal,char,bool 和 struct 统称为值类型。所有的值类型都是隐式密封的(sealed)(无法派生出新的值类型),目的是防止其他任何类型从值类型进行派生。  值类型变量声明后,不管是否已经赋值,编译器为其分配内存。

C#的所有值类型均隐式派生自System.ValueType:

结构体:struct(直接派生于System.ValueType);
数值类型:

  • 整型:sbyte(System.SByte的别名),short(System.Int16),int(System.Int32),long(System.Int64),byte(System.Byte),ushort(System.UInt16),uint(System.UInt32),ulong(System.UInt64),char(System.Char);
  • 浮点型:float(System.Single),double(System.Double);
  • decimal(System.Decimal),用于财务计算的高精度。
  • bool型:bool(System.Boolean的别名);
  • struct(派生于System.ValueType)。
  • enum(派生于System.Enum);
  • 可空类型(派生于System.Nullable<T>泛型结构体,T?实际上是System.Nullable<T>的别名)。

值得注意的是,引 用类型和值类型都继承自System.Object类。不同的是,几乎所有的引用类型都直接从System.Object继承,而值类型则继承其子类,即 直接继承System.ValueType。System.ValueType直接派生于System.Object。即System.ValueType本身是一个类类型,而不是值类型。其关键在于ValueType重写了Equals()方法,从而对值类型按照实例的值来比较,而不是引用地址来比较。

可以用Type.IsValueType属性来判断一个类型是否为值类型:

TestType testType = new TestType ();
if (testTypetype.GetType().IsValueType)
{
     Console.WriteLine("{0} is value type.", testType.ToString());
}

引用类型

引用类型的变量持有的是数据的引用,数据存储在数据堆中,string 和 class统称为引用类型。当声明一个类时,只在栈中分配一小片内存用于容纳一个地址,而此时并没有为其分配堆上的内存空间。当使用 new 创建一个类的实例时,分配堆上的空间,并把堆上空间的地址保存到栈上分配的小片空间中。

C#有以下一些引用类型:

  • 数组(派生于System.Array)
  • 用户用定义的以下类型:
  • 类:class(派生于System.Object);
  • 接口:interface(接口不是一个“东西”,所以不存在派生于何处的问题。Anders在《C# Programming Language》中说,接口只是表示一种约定[contract]);
  • 委托:delegate(派生于System.Delegate)。
  • object(System.Object的别名);
  • 字符串:string(System.String的别名)。

string的探索

明明string赋值都是值类型,咋就是引用类型呢?

.net框架程序设计(修订版)中有这样一段描述:

string 类型直接继承Object,这使得它成为一个引用类型,也就是说线程的堆栈上不会驻留任何字符串。

名称

CTS类型

说明

string

System.String

Unicode字符串

string s1 = "aaaa";
 
string s2 = s1;
 
Console.WriteLine("s1:" + s1);
 
Console.WriteLine("s2:" + s2);
 
s1 = "bbbb";
 
Console.WriteLine("s1:" + s1);
 
Console.WriteLine("s2:" + s2);
 
Console.ReadKey();

在String字符串上,最开始S1地址指向aaaa,由于S2=S1,所以S2地址也同样指向aaaa。如图所示

当给S1再次赋值bbbb时,堆中就会开辟出数据bbbb,而且aaaa数据没有消失,没有被覆盖。S1地址就会指向堆中bbbb

S2地址还是指向aaaa。如图所示

上面代码值类型的赋值,但string是一个引用类型。String被分配在堆上,而不是栈上。因此,当把一个字符串变量赋给另一个字符串时,会得到对内存中同一个字符串的两个引用。但是,string与引用类型在常见的操作上有一些区别。例如字符串是不可改变的。修改其中一个字符串,就会创建一个全新的string对象,而另一个字符串不会发生任何变化。

3.通用系统类型(CTS)

C#的基本数据类型都以与平台无关的方式来定义。C#的预定义类型并没有内置于语言中,而是内置于.NET Framework中。所有面向.NET的语言都最终被编译为IL。

例如,在C#中声明一个int变量时,声明的实际上是CTS中System.Int32的一个实例。这具有重要的意义:
确保IL上的强制类型安全;
实现了不同.NET语言的互操作性;
所有的数据类型都是对象。它们可以有方法,属性,等。例如:ToString()。

4.值类型和引用类型在内存中的部署

栈和堆的了解

栈只能在一端对数据进行操作,也就是栈顶端进行操作。’

栈也是一种内存自我管理的结构,压栈自动分配内存,出栈自动清空所占内存。

  另外值得注意的两点:

     1.栈中的内存不能动态请求,只能为大小确定的数据分配内存,灵活性不高,但是栈的执行效率很高

     2.栈的可用空间并不大,所以我们在操作分配到栈上的数据时要注意数据的大小带来的影响。

   堆与栈有所区别,堆在C#中用于存储实实例对象,能存储大量数据,而且堆能够动态分配存储空间

   相比栈只能在一端操作,堆中的数据可以随意存取

   但堆的结构使得堆的执行效率不如栈高,而且不能自动回收使用过的对象。对于堆中的内存回收,C++程序员需要进行手动回收,这也是C++编程值得注意的一点,否则很容易造成内存溢出。而对于.NET程序员,平台提供了垃圾回收(GC)机制,可以自动回收堆中过期的对象。

值类型和引用类型在栈和堆中的分配

这儿有两个原则:

    (1)创建引用类型时,runtime会为其分配两个空间,一块空间分配在堆上,存储引用类型本身的数据,另一个块空间分配在栈上,存储对堆上数据的引用(实际上存储的堆上的内存地址,也就是指针)。

    (2)创建值类型时, runtime会为其分配一个空间,这个空间分配在变量创建的地方,如:

      如果值类型是在方法内部创建,则跟随方法入栈,分配到栈上存储。

      如果值类型是引用类型的成员变量,则跟随引用类型,存储在堆上。

更加详细的介绍参考:https://blog.csdn.net/qiaoquan3/article/details/51202926

5.值类型与引用类型适用场合

值类型在内存管理方面具有更好的效率,并且不支持多态,适合用做存储数据的载体;引用类型支持多态,适合用于定义应用程序的行为。

在C#中,我们用struct/class来声明一个类型为值类型/引用类型。考虑下面的例子:
SomeType[] oneTypes = new SomeType[100];
如 果SomeType是值类型,则只需要一次分配,大小为SomeType的100倍。而如果SomeType是引用类型,刚开始需要100次分配,分配后 数组的各元素值为null,然后再初始化100个元素,结果总共需要进行101次分配。这将消耗更多的时间,造成更多的内存碎片。所以,如果类型的职责主 要是存储数据,值类型比较合适。
一般来说,值类型(不支持多态)适合存储供 C#应用程序操作的数据,而引用类型(支持多态)应该用于定义应用程序的行为。通常我们创建的引用类型总是多于值类型。如果满足下面情况,那么我们就应该创建为值类型:
该类型的主要职责用于数据存储。 
该类型的共有接口完全由一些数据成员存取属性定义。 
该类型永远不可能有子类。 
该类型不具有多态行为。
 

参考

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

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

C#中string类型是值类型还是引用类型?

C#详解值类型和引用类型区别

发布了30 篇原创文章 · 获赞 1 · 访问量 1158

猜你喜欢

转载自blog.csdn.net/chunchunlaila/article/details/105472903