根据它们在内存中存储值的方式进行分类。 C# 数据类型有下面的三种分类:
当我们的代码执行时,内存中有两个地方用来存储这些代码。分别是栈和堆。栈和堆都用来帮助我们运行代码的,它们驻留在机器内存中,且包含所有代码执行所需要的信息。
栈是编译期间就分配好的内存空间,因此你的代码中必须就栈的大小有明确的定义;堆是程序运行期间动态分配的内存空间,你可以根据程序的运行情况确定要分配的堆内存的大小 存放在栈中时要管存储顺序,保持着先进后出的原则,他是一片连续的内存域,有系统自动分配和维护。
而堆是无序的,他是一片不连续的内存域,有用户自己来控制和释放,如果用户自己不释放的话,当内存达到一定的特定值时,通过垃圾回收器(GC)来回收。
值类型的数据是放在栈当中的。(因为它在定义的时候就可以知道它的具体大小了),(也叫放在自己声明的位置,要结合程序是如何运行的来理解)
例如,考虑整数变量 int i = 100;
系统在为变量 i 分配的内存空间中存储 100。 下图说明了 100 是如何存储在内存中的某个假设位置 (0x248120) 的“i”的:
值类型都是继承于System.ValueType
(System.ValueType也是继承于System.Object)
下面的这些都是值类型
static void ChangeValue(int x)
{
x = 200;
Console.WriteLine(x); //200
}
static void Main(string[] args)
{
int i = 100;
Console.WriteLine(i); //100
ChangeValue(i);
Console.WriteLine(i); // 100
}
例 2
static void Main(string[] args)
{
int i = 100;
int b = i;
Console.WriteLine(b); // 100
b = 300;
Console.WriteLine(b); // 300
Console.WriteLine(i); // 100
}
与值类型不同,引用类型不直接存储其值。 相反,它存储存储值的地址。 换句话说,引用类型包含一个指向保存数据的另一个内存位置的指针(放在堆中)。
例如,考虑以下字符串变量:
string s = "Hello World!!";
下图显示了系统如何为上述字符串变量分配内存。
如上图所示,系统为变量 s 在栈中选择一个随机位置 (0x248100)。 一个变量s的值为0x700000,即实际数据值的内存地址。 因此,引用类型存储实际值存储位置的地址,而不是值本身。
下面的这些都是引用类型
当您将引用类型变量从一种方法传递到另一种方法时,它不会创建新副本; 相反,它传递变量的地址。 所以,如果我们在一个方法中改变了一个变量的值,它也会反映在调用方法中。 (在同一个方法中也是一样的)。
class Program
{
static void ChangeReferenceType(Student std2)
{
std2.Age = 200;
}
static void Main(string[] args)
{
Student std1 = new Student();
std1.Age = 100;
ChangeReferenceType(std1);
Console.WriteLine(std1.Age);//200
var std2 = std1; //改的是std2的值,但是std1的值也变了。
std2.Age = 300;
Console.WriteLine(std1.Age);//300
}
}
public class Student
{
public int Age { get; set; }
}
特例 String 是一种引用类型,但它是不可变的。 这意味着一旦我们分配了一个值,它就无法更改。 如果我们更改一个字符串值,那么编译器会在内存中创建一个新的字符串对象,并将一个变量指向新的内存位置。 因此,将字符串值传递给函数会在内存中创建一个新变量,函数中值的任何更改都不会反映在原始值中,如下所示。 (表现形式跟值类型一样了)
static void ChangeReferenceType(string name)
{
name = "Steve";
}
static void Main(string[] args)
{
string name = "malema.net";
ChangeReferenceType(name);
Console.WriteLine(name); //malema.net
}
引用类型变量未初始化时的默认值为 null。 Null 表示不引用任何对象。 (以后程序会经常的碰到未将对象引用设置到对象实例,就是这个对象变成了null) 值类型变量不能为null,因为它保存的是值,而不是内存地址。 C# 2.0 引入了可空类型,您可以使用它为值类型变量分配 null 或声明值类型变量而不为其分配值。