C# 值类型和引用类型

在C#中,根据这些数据类型在内存中存储值的方式对它们进行分类。C#包括以下类别的数据类型:

  1. 值类型

  2. 引用类型

  3. 指针类型

值类型

如果数据类型在其自己的内存空间中保存数据值,则它是一种值类型。这意味着这些数据类型的变量直接包含值。

所有值类型都从System.ValueType派生,而System.ValueType又从System.Object派生。

例如,整数变量 int i = 100;

系统将100存储在为变量 i 分配的内存空间中。下图说明了如何将100存储在“i”的内存(0x239110)中的某个假设位置:

值类型变量的内存分配

以下数据类型均为值类型:

  • bool

  • byte

  • char

  • decimal

  • double

  • enum

  • float

  • int

  • long

  • sbyte

  • short

  • struct

  • uint

  • ulong

  • ushort

传递值类型变量

  当您将值类型的变量从一种方法传递到另一种方法时,系统会在另一种方法中创建变量的单独副本。如果在一个方法中更改了值,则不会影响另一方法中的变量。

static void ChangeValue(int x)
{
    x =  200;

    Console.WriteLine(x);
}

static void Main(string[] args)
{
    int i = 100;

    Console.WriteLine(i);
    
    ChangeValue(i);
    
    Console.WriteLine(i);
}
输出:

100
200
100

在上面的示例中,即使在将 Main ()方法中的变量 i 传递给 ChangeValue ()方法并更改其值之后,它仍然保持不变。

引用类型

与值类型不同,引用类型不会直接存储其值。相反,它存储正在存储值的地址。换句话说,引用类型包含指向另一个保存数据的存储位置的指针。

例如,以下字符串变量:

string s = "Hello World!!";

下图显示了系统如何为上述字符串变量分配内存。

引用类型变量的内存分配

如上图所示,系统为变量s选择内存中的随机位置(0x803200)。变量s的值为0x600000,这是实际数据值的内存地址。因此,引用类型存储实际值所在位置的地址,而不是值本身。

以下是引用类型数据类型:

  • 字符串

  • 数组(即使它们的元素是值类型)

  • 委托

传递引用类型变量

当您将引用类型变量从一个方法传递到另一个方法时,它不会创建新的副本; 相反,它会传递变量的地址。因此,如果我们改变方法中变量的值,它也会反映在调用方法中。

static void ChangeReferenceType(Student std2)
{
    std2.StudentName = "Steve";
}

static void Main(string[] args)
{
    Student std1 = new Student();
    std1.StudentName = "Bill";
    
    ChangeReferenceType(std1);

    Console.WriteLine(std1.StudentName);
}
输出:
Steve

在上面的示例中,我们将 Student 对象 std1 传递给ChangeReferenceType()方法。在这里,它实际上传递std1的内存地址。因此,当ChangeReferenceType()方法更改StudentName时,它实际上是在更改std1对象的StudentName,因为std1和std2都指向内存中的同一地址。

Null 值

  引用类型变量的默认值null是未初始化时。 Null表示不引用任何对象。

空引用类型

值类型变量不能为null,因为它保存值而不是内存地址。C#2.0引入了可为空的类型,使用它可以为值类型变量分配null或声明值类型变量而无需为其分配值。