不要忽视基础:理解 C# 中的类型

发布: (2026年2月2日 GMT+8 15:31)
10 分钟阅读
原文: Dev.to

Source: Dev.to

请提供您希望翻译的完整文本(除代码块和 URL 之外的内容),我将把它翻译成简体中文并保持原有的 Markdown 格式。谢谢!

介绍

理解类型是 C# 中最重要的基础之一。每一种类型,无论是什么,最终都关联到一个称为 System.Object 的“大老板”类型。这意味着在幕后,所有类型共享一些共同特性。

示例

// This class automatically inherits from System.Object
class Music { }

// This is the same as above, just written out
class Opera : System.Object { }

无论你创建什么,都是从 System.Object 开始的。这为每个对象提供了诸如 ToString()GetHashCode() 等有用的方法。

C# 中的类型:基础

在 C# 中,类型分为两大类:

  • 值类型
  • 引用类型

还有一个特殊的组,称为 原始类型,它们是最基本的内置类型。

让我们来逐一拆解!

原始类型

原始类型是 C# 内置的最简单的类型。它们对编译器友好,并直接映射到 .NET 框架中的类型。

示例: int, double, bool, char, byte, short, long, float, decimal

  • 原始类型是值类型的一个子集。
  • 它们有默认值(int0boolfalse,等等)。
  • 它们运行快速且高效。
int   count = 5;    // int is a primitive type
bool  isOn = true; // bool is a primitive type

值类型

值类型直接保存它们的实际数据。它们存放在一个叫做 的快速访问区域。当你把一个值类型赋给另一个变量时,会复制该值。

示例: 所有原始类型、structenum

  • 值类型始终拥有一个值,即使你没有显式设置。
  • 它们不能为 null(除非使用可空类型)。
  • 赋值会复制值——而不是仅复制引用。

所有值类型(structenum、原始类型)都继承自 System.ValueType

int number = 10;          // 值类型,如果未设置默认值为 0
int copy   = number;      // 复制值 (10)

为什么值类型是 sealed 的?

  • 布局不可变性: 它们的内存布局是固定的;如果允许继承,大小和结构将变得不可预测。
  • 性能: sealed 的特性让运行时能够优化存储和访问。
  • 简洁性: 让值类型可以继承会使赋值、装箱和拆箱变得复杂。

下面的代码无法编译:

struct BasePoint { public int X, Y; }

// 错误!不能从 sealed 类型派生
struct DerivedPoint : BasePoint { public int Z; }

你也不能把值类型作为引用类型的基类:

struct BaseStruct { }

// 错误!不能从值类型派生
class MyClass : BaseStruct { }

如何创建自己的值类型

使用 struct

struct 是用户自定义的值类型。下面是一个简单的二维点:

public struct Point
{
    public int X;
    public int Y;

    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }
}
Point a = new Point(1, 2);
Point b = a;   // 复制值(而不是引用)
b.X = 10;

// a.X 仍然是 1,b.X 是 10

使用 enum

所有枚举都继承自抽象的 System.Enum 类型,而 System.Enum 本身又继承自 System.ValueTypeenum 是另一种可以创建的值类型:

public enum DayOfWeek
{
    Sunday,
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday
}
  • structenum 是创建自定义值类型的唯一方式。
  • 值类型存放在栈上(或对象内部的内联位置),其行为与引用类型(类)不同。
  • 不能从 structenum 派生,也不能让它们继承除 System.ValueType 之外的任何类型。

可空值类型

有时你希望值类型能够持有 null(例如,当值尚未设置时)。在 C# 中,你可以使用 可空 类型来实现:

int? score = null; // 'score' can now be null

if (score == null)
{
    Console.WriteLine("No score yet!");
}

引用类型

引用类型存储对其数据的引用(地址)。实际的数据位于 上,变量仅指向它。将引用类型赋值给另一个变量时,复制的是引用,而不是实际的数据。

示例: classstringarraydelegateinterfaceobject

  • 引用类型可以为 null(它们可能不指向任何对象)。
  • 在引用类型未赋值之前使用会导致 NullReferenceException
  • 赋值操作复制的是引用(地址),而不是数据本身。
string name; // 默认情况下为 null

// 在赋值之前使用 'name' 会导致错误
// Console.WriteLine(name.Length); // NullReferenceException!

内存分配方式:值类型 vs 引用类型

方面值类型引用类型
位置栈(或在另一个对象内部内联)堆(由垃圾回收器管理)
赋值复制实际数据复制引用(指针)
默认值零初始化(例如 0falsenull
可空性除非包装(如 int?),否则不可为空可以为 null
继承继承自 System.ValueType(sealed)继承自 System.Object

理解这些差异有助于编写更高效、可预测且无错误的 C# 代码。

Source:

值类型与引用类型的区别

值类型和引用类型的主要区别在于 它们在内存中的存储方式和位置

值类型 – 存储在栈上

值类型通常存放在栈中——这是一块快速且简单的内存。当你创建一个值类型变量时,数据就直接保存在该变量本身中。

Value type memory layout

示例

int number = 5;
int age    = 20;

每个变量都直接保存自己的值。

引用类型 – 引用与对象位置

引用类型将 实际的对象数据 存放在 上,但 引用(指向对象的变量)可以存放在多个位置:

引用声明的位置引用所在的位置
方法内部的局部变量
类/结构体的字段所在对象内部(通常在堆上)
static 字段特殊的静态内存区域

无论引用存放在哪里,它始终指向堆上的对象数据。

Reference type memory layout 1

Reference type memory layout 2

示例

class Pet    { public string Name; }
class Person { public Pet pet; }

void Example()
{
    Person p = new Person(); // ‘p’ 是局部变量(引用存放在栈上)
    p.pet = new Pet();       // ‘pet’ 是字段(引用存放在堆上的 Person 对象内部)
}
  • p(指向 Person 对象的引用)位于栈上,因为它是局部变量。
  • Person 对象本身位于堆上。
  • Person 对象内部,pet 字段保存的引用指向另一个堆分配的对象(Pet)。

当你进行复制时会发生什么?

值类型复制

int a = 10;
int b = a; // b gets its own copy of the value (10)

值类型复制示意图

引用类型复制

Person p1 = new Person();
Person p2 = p1; // p2 points to the same object as p1

引用类型复制示意图

p1p2 都引用内存中的 同一个 对象。通过任一变量修改对象时,另一变量访问时也会看到相同的更改。

摘要

  • 原始类型intbool 等)是内置的 值类型
  • 值类型 保存实际数据,并位于 上。
  • 引用类型 保存一个引用(地址)。该引用可以存放在栈、堆或静态区域,但 对象数据始终位于堆上
  • 值类型 赋值会复制数据;为 引用类型 赋值会复制地址。
  • C# 中的所有类型最终都派生自 System.Object

初学者的额外提示

  • A NullReferenceException means you tried to use a reference type that hasn’t been instantiated.
    NullReferenceException 表示你尝试使用了尚未实例化的引用类型。

  • Use nullable value types (int?, double?, …) when you need a value type that can also be null.
    → 当你需要一个也可以为 null 的值类型时,使用可空值类型(int?double?、…)。

  • Passing a value type to a method copies its value; passing a reference type copies the reference.
    → 将 值类型 传递给方法会复制其值;将 引用类型 传递给方法会复制引用。

Understanding these basics will help you write safer and more efficient C# code. Happy coding!
理解这些基础知识将帮助你编写更安全、更高效的 C# 代码。祝编码愉快!

Back to Blog

相关文章

阅读更多 »

C# 中的方法和参数使用

定义和调用方法 csharp static void Greet { Console.WriteLine'Hello!'; } static void Main { Greet; // 方法调用 } // 输出: Hello! 方法...

运算符

什么是 Java 中的运算符?运算符是用于对变量和数值执行操作的符号。Java 中运算符的类型——算术运算符——赋值运算符……