news 2026/4/16 9:50:03

# 深入解析 C# 中类(class)与结构(struct)的异同

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
# 深入解析 C# 中类(class)与结构(struct)的异同

在 C# 这门以类型系统著称的面向对象语言中,class(类)struct(结构)是两种最核心、也最容易被混淆的类型定义方式。

它们都可以封装数据与行为,但在内存模型、语义设计、继承能力、性能特征等方面存在本质差异。理解这些差异,不仅关系到代码正确性,更直接影响系统性能与可维护性。


一、共同点:class 与 struct 能做什么是一样的?

尽管底层语义不同,class 与 struct 在语言层能力上高度一致:

  • 封装能力

    • 都可以定义字段(Field)、属性(Property)、方法(Method)、索引器(Indexer)、事件(Event)
    • 均支持运算符重载
  • 接口实现

    • 都可以实现一个或多个接口(Interface)
  • 访问控制

    • 支持public/private/protected/internal
  • 泛型支持

    • 都可作为泛型参数
    • 都可定义为泛型类型(class<T>/struct<T>
  • 构造函数

    • 都支持参数化构造函数(struct 有额外约束)

👉结论

从“能写什么代码”来看,class 与 struct 非常相似;
真正的差异,来自于它们的类型语义与内存模型


二、本质差异:引用类型 vs 值类型

维度classstruct
类型本质引用类型(Reference Type)值类型(Value Type)
默认内存位置托管堆(Heap)取决于宿主(通常为栈)
继承能力支持单继承不支持继承(隐式继承 ValueType)
构造函数可自定义无参 / 有参不可自定义无参,必须初始化全部字段
析构函数支持(由 GC 调用)不支持
赋值语义引用拷贝值拷贝
可空性默认可为null默认不可为null
GC 影响需要 GC 回收栈上无 GC,堆上随宿主回收
装箱拆箱不存在转 object / interface 会发生

三、几个最容易踩坑的关键差异

1️⃣ 值拷贝 vs 引用拷贝(核心中的核心)

Animal a1 = new Animal("Dog"); Animal a2 = a1; a2.Species = "Husky"; Console.WriteLine(a1.Species); // Husky
  • class:变量中存的是引用地址
  • 多个变量 → 同一个对象
Cat c1 = new Cat("橘猫"); Cat c2 = c1; c2.Name = "布偶猫"; Console.WriteLine(c1.Name); // 橘猫
  • struct:变量中存的是完整数据副本
  • 修改副本不会影响原值

⚠️ 注意:值拷贝 ≠ 逻辑深拷贝

  • 如果 struct 内部包含引用类型字段,只会拷贝引用本身

2️⃣ struct 的内存位置并不“一定在栈上”

struct 的存储位置,取决于它的宿主
  • 局部变量 → 通常在栈
  • class 字段 → 在堆
  • 数组元素 → 在堆
  • async / iterator → 可能被提升到堆

👉不要用“struct 在栈上 / class 在堆上”作为绝对判断


3️⃣ struct 的构造函数限制

struct Point { public int X; public int Y; public Point(int x, int y) { X = x; Y = y; // 必须初始化所有字段 } }
  • ❌ 不允许自定义无参构造函数
  • ✅ 参数化构造函数必须初始化全部字段
  • 编译器始终保留一个“零值初始化路径”

四、代码对比示例(精简直观)

// struct:值语义 struct Cat { public string Name; public Cat(string name) => Name = name; } // class:引用语义 class Animal { public string Species; public Animal(string species) => Species = species; }
Cat c1 = new Cat("A"); Cat c2 = c1; c2.Name = "B"; // c1 不受影响 Animal a1 = new Animal("Dog"); Animal a2 = a1; a2.Species = "Cat"; // a1 被影响

五、如何选择?实战决策指南

✅ 优先选择 struct 的场景

  • 小而简单的数据结构(2~4 个字段)
  • 强调值语义(数学、坐标、金额)
  • 高频创建、短生命周期
  • 不可变对象(readonly struct)

典型示例:

  • int/DateTime/Guid
  • Point/Vector/Color

✅ 优先选择 class 的场景

  • 复杂业务对象
  • 需要继承 / 多态
  • 生命周期较长
  • 需要 null 表示“不存在”

典型示例:

  • User/Order
  • Service/Controller
  • 领域模型(Domain Model)

六、面试高频问题(附标准回答)

下面问题均来自C# / .NET 中高级面试真实高频题,可直接背诵使用。


Q1:class 和 struct 的本质区别是什么?

标准回答:

class 是引用类型,struct 是值类型。
class 变量保存的是对象引用,多个变量可指向同一实例;
struct 变量保存的是实际数据,赋值会产生值拷贝。


Q2:struct 一定分配在栈上吗?

标准回答:

不一定。struct 的存储位置取决于它的宿主。
作为局部变量时通常在栈上,作为类字段或数组元素时分配在堆上。


Q3:为什么 struct 不支持继承?

标准回答:

struct 的设计目标是轻量级值语义,如果允许继承会引入对象身份、多态和额外间接层,破坏其性能和语义一致性。


Q4:什么时候不应该使用 struct?

标准回答:

当对象体积较大、需要继承、多态,或生命周期较长时,不应使用 struct,否则会导致频繁值拷贝和性能下降。


Q5:struct 作为方法参数时会发生什么?

标准回答:

默认情况下会发生值拷贝,方法内部修改不会影响原变量。
可通过ref/in/out传递以避免拷贝。


Q6:什么是装箱和拆箱?什么时候发生?

标准回答:

当 struct 被转换为 object 或接口类型时会发生装箱(值复制到堆)。
从 object 再转回 struct 时发生拆箱。
装箱拆箱会产生额外分配和性能开销。


Q7:为什么 struct 不能定义无参构造函数?

标准回答:

因为 CLR 必须保证所有 struct 都可以被零值初始化,允许自定义无参构造函数会破坏这一约定。


Q8:readonly struct 有什么作用?

标准回答:

readonly struct 保证实例不可变,可避免 defensive copy,提高性能和线程安全性。


Q9:record struct 和 record class 有什么区别?

标准回答:

record struct 是值语义,record class 是引用语义。
二者都提供值相等性、解构和 with 表达式,但内存与拷贝语义不同。


Q10:实际项目中如何选择 class 还是 struct?

标准回答:

判断标准不是性能,而是语义:

  • 需要对象身份、继承、多态 → class
  • 表示纯数据、值语义、短生命周期 → struct

七、一句话总结(面试 & 记忆版)

class = 引用语义 + 继承 + 复杂对象
struct = 值语义 + 轻量数据 + 性能友好

终极判断标准:

👉你关心的是“对象身份”,还是“数据本身”?

class = 引用语义 + 继承 + 复杂对象
struct = 值语义 + 轻量数据 + 性能友好

选择标准不是“性能迷信”,而是:

👉你要的是“对象身份”,还是“数据本身”?

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 12:31:25

2026毕设ssm+vue基于高校新生报到论文+程序

本系统&#xff08;程序源码&#xff09;带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容一、选题背景关于动漫信息管理与展示系统的研究&#xff0c;现有研究主要以综合性内容管理系统或单一功能模块为主&#xff0c;专门针对动漫…

作者头像 李华
网站建设 2026/4/16 12:31:29

【ACWing】111. 畜栏预定

题目地址&#xff1a; https://www.acwing.com/problem/content/113/ 有NNN头牛在畜栏中吃草。每个畜栏在同一时间段只能提供给一头牛吃草&#xff0c;所以可能会需要多个畜栏。给定NNN头牛和每头牛开始吃草的时间AAA以及结束吃草的时间BBB&#xff0c;每头牛在[A,B][A,B][A,…

作者头像 李华
网站建设 2026/4/13 8:28:34

2026毕设ssm+vue基于动漫论坛系统论文+程序

本系统&#xff08;程序源码&#xff09;带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容一、选题背景 关于“基于 SSMVUE 的动漫文化社区”问题的研究&#xff0c;现有研究主要以“泛娱乐社交平台”或“单一技术栈&#xff08;Sp…

作者头像 李华
网站建设 2026/4/16 13:29:46

kotin基础语法汇总

变量声明 Kotlin 中使用 val 和 var 声明变量&#xff0c;val 表示不可变变量&#xff08;类似 Java 的 final&#xff09;&#xff0c;var 表示可变变量。 val name: String "Kotlin" // 不可变 var age: Int 10 // 可变类型可以省略&#xff0c;编译器会自动推…

作者头像 李华
网站建设 2026/4/15 15:22:20

基于单片机的蔬菜大棚温湿度远程测报系统设计

系统总体设计概述 点击链接下载设计资料&#xff1a;https://download.csdn.net/download/m0_51061483/92081514 1.1 设计背景与应用意义 随着现代农业向规模化、智能化方向不断发展&#xff0c;蔬菜大棚已经成为保障农作物稳定生产和反季节供应的重要设施。蔬菜生长过程对环…

作者头像 李华