在C#中,根据这些数据类型在内存中存储值的方式对它们进行分类。C#包括以下类别的数据类型:
值类型
引用类型
指针类型
如果数据类型在其自己的内存空间中保存数据值,则它是一种值类型。这意味着这些数据类型的变量直接包含值。
所有值类型都从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,因为它保存值而不是内存地址。C#2.0引入了可为空的类型,使用它可以为值类型变量分配null或声明值类型变量而无需为其分配值。