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

C# 中类(class)与结构(struct)的深度解析 在 C# 和 .NET 生态系统中,类(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 = 值语义 + 轻量数据 + 性能友好

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

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

在运行opencv时出现的两个问题:AttributeError: module ‘cv2‘ has no attribute ‘gapi_wip_gst_GStreamerPipeline‘ 解决了opencv的两个问题:由问题一引出 AttributeError: module 'cv2' has no attribute 'gapi_wip_gst_GStreamerPipeline' cv2.error:OpenCV(4.1.2)C:\projects\opencvpython\opencv\modules\highgui\src\window.cpp:717:error: (-2:Unspecified error) The function is not implemented... 阅读详情

相关推荐

Unity开源游戏源码精选:17个亲测可运行教学项目

Unity游戏开发中,掌握真实项目结构与工程实践远比熟记API更重要。本文围绕‘Unity开源项目’和‘游戏源码’两大核心概念,解析高质量开源资源的本质特征——结构清晰、逻辑可溯、修改即时反馈。从基础的MonoBehaviour生命周期组织,到进阶的ScriptableObject数据驱动、事件总线解耦,再到架构级的DOTS ECS设计与网络同步模式,技术价值在于将抽象原理落地为可调试、可验证、可迁移的代码范式。适用于新手建立开发直觉、中级开发者突破系统设计瓶颈,以及团队构建可维护框架。所有项目均基于Uni

weixin_31528001的博客 716

C#结构(Struct)和类(class)的区别

C#结构(Struct)和类(class)的区别

尽早点完技能点,升到顶级。 2061

一文入门Qwen-Agent【附实战代码】

Qwen-Agent 是一个开源框架,用于开发基于 Qwen 模型的 AI 智能体应用,一文带你入门使用

m0_55303420的博客 1873

C#中struct和class的区别

本文详细分析了C#中struct和class的区别,对于C#初学者来说是有必要加以了解并掌握的。 简单来说,struct是值类型,创建一个struct类型的实例被分配在栈上。class是引用类型,创建一个class类型实例被分配在托管堆上。但struct和class的区别远不止这么简单。 概括来讲,struct和class的不同体现在: ● 类是引用类型,struct是值类型 ● 在托管堆

hatch gavin的专栏 1283

手把手教你用AppsFlyer SDK实现延迟深度链接(附Android/iOS代码示例)

本文详细介绍了如何使用AppsFlyer SDK实现延迟深度链接,提供Android和iOS双平台代码示例,帮助开发者解决跨平台精准跳转与用户归因问题。通过实战案例和高级场景分析,提升应用的用户转化率和广告投放效果。

sre5engineer的博客 696

高德地图爬虫

高德地图爬虫 工具:Pycharm,win10,Python3.6.4 1.需求分析 这篇爬虫和上一篇百度地图爬虫要求一样,百度地图爬虫我发现有一个auth参数会一直变化,一旦变化则获取的数据是不准确的,所以我上高德地图看了一下,高德地图没有这个反爬机制。但是高德地图大概爬取120个页面就会跳一次验证码,我这里是通过换IP解决这个问题的。 2.数据准备 同样我们需要全国地级市信息,用之前...

123的博客 1万+

C#重点问题之Struct和Class的异同

介绍struct和class的相同点和不同点, 以及值类型和引用类型的基础原理和概念等.

木头圈 2819

从‘炼丹’到‘讲理’:物理信息神经网络(PINN)的硬约束 vs 软约束,我该选哪个?

本文深入探讨了物理信息神经网络(PINN)中硬约束与软约束的选择策略,帮助研究者在深度学习中有效融入物理先验知识。通过对比两种约束方法的实现复杂度、数据效率和计算性能,提供了针对材料科学和流体动力学等领域的实用决策指南,并介绍了自适应约束和混合约束等前沿技术。

weixin_42535703的博客 526

C# struct, class的区别

特性class(引用类型)struct(值类型)内存分配堆栈生命周期管理垃圾回收器管理自动销毁(超出作用域时销毁)是否支持继承支持继承不支持继承默认值null所有字段初始化为零值是否实现接口可以实现多个接口可以实现多个接口赋值与传递传递引用(引用类型)传递值(复制数据)适用场景适用于较复杂的对象,涉及共享数据和继承的场景适用于小型数据结构,要求高效的复制与传递的场景内存效率内存分配较慢,需要垃圾回收内存分配较快,不涉及垃圾回收在选择使用class还是struct。

qq_41328432的博客 1522

2023华为od机试C卷【宽度最小的子矩阵】Python 实现

给定一个矩阵,包含N*M个整数,和一个包含K个整数的数组现在要求在这个矩阵中找一个宽度最小的子矩阵,要求子矩阵包含数组中所有的整数。

MISAYAONE的博客 2185

【VisDrone数据集】YOLOX训练VisDrone数据集步骤与结果

YOLOX训练VisDrone数据集步骤与结果。

Gorgeous_wxd 2233

C#值类型与引用类型

概要: C#中将数据类型分为值类型(value type)和引用类型(reference type) 值类型: 值类型变量直接包含其本身的数据。在定义一个值类型变量后,将直接为该变量分配空间,可以直接赋值和使用。 列举值类型: eg: 用变量“a”为变量“b”赋值,是将“a”所在内存的值复制给“b”。执行 b=50之后,因为不在同一内存空间,所以b的值为50,a的值仍为100 引用类型: 引用类型变量本身并不包含数据,只是存储对数据的引用,数据保存在其他位置。引用类型变量在定义时并不会分配空间,只是在

chinaherolts2008的博客 470

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

RustTraining 项目解读:为 C 开发者编写的 Rust 全面迁移指南——从 GC 思维、类型系统到并发与工程实践

> 本文以 [RustTrainingForCSharp.md](https://link.gitcode.com/i/975d89d2bae937f35dc83bf16d5d04ab) 为主干,系统梳理这套面向 C# 程序员的 Rust 训练材料:它覆盖语言哲学(GC vs RAII)、类型系统(Option/Result、穷尽模式匹配、真不可变)、范式迁移(继承→组合、接口→trait)、错误

gitblog_00513的博客 484

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

链表遍历与插入节点:从原理到实战的完整指南

数据结构是计算机科学的核心基础,它研究数据的组织、存储与操作方式,直接影响程序的效率与性能。其中,链表作为一种基础且重要的线性数据结构,通过节点与指针(或引用)实现了动态内存分配与高效的元素增删。其核心原理在于利用指针将离散的内存块串联,避免了数组连续存储的局限性,从而在频繁插入删除的场景下展现出O(1)的时间复杂度优势。这一特性使其在实现内存池、任务调度队列、LRU缓存等需要动态调整数据规模的工程实践中具有重要技术价值。理解链表的遍历与节点插入操作,是掌握其动态性、攻克指针操作边界条件(如空指针、头尾节点

weixin_30561425的博客 411

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Java秋招八股之王——拿不到大厂Offer来找我(全文14w字,持续更新)

如果你需要一套八股文,想要一套八股文解决秋招的大部分问题,来看看这篇文章吧~内容包含数据结构、计算机网络、数据库、Redis、消息队列、JavaSE、JVM、JUC、海量数据题目、高并发场景、项目的亮点难点、ssm框架、dubbo框架等等。这是我整个秋招不停面试的总结和反思,最后也是靠它拿到了菜鸟的offer,希望会对后面秋招的朋友起到一些帮助。

qq_40460454的博客 1291

C# 面试问题大全:008.类(class)和结构(struct)的详细区别是什么?

类:引用类型,适用于复杂、大型对象,支持继承和多态,适合用于需要共享状态和动态扩展的场景。结构:值类型,适用于小型、轻量级对象,性能更高,但不支持继承和多态,适合用于简单的数据容器和性能敏感的应用。

caifox的博客 1393

C#基础:类class与结构struct的区别

一般来说,某个类对象使用另一个类的对象赋值时,则两者共用一个内存地址【节约内存空间】,ReferenceEquals引用比较此时返回true类的构造函数(构造方法)如果一个类没有显示定义构造函数,则默认有一个无参构造函数,如果一个类已定义了带参数的构造函数,如果不手动定义无参构造函数,则没有无参构造函数。

ylq1045的专栏 1388

【C#】类与结构体的区别

Console . WriteLine("大家好,我是练习时长" + stuTime + "的" + name);} }Console . WriteLine("大家好,我是练习时长" + stuTime + "的" + name);} }从语法上来看,它们有异曲同工之妙,类里面的成员几乎都可以定义在结构体中。

Wilhelm的博客 1828

C#详解struct和class的区别

可以从数据类型、访问权限(封装)、继承、构造函数、实例化方面做比较 3.struct 默认的访问权限是public,而class默认的访问权限是private. 简单来说,struct是值类型,创建一个struct类型的实例被分配在栈上。class是引用类型,创建一个class类型实例被分配在托管堆上。但struct和class的区别远不止这么简

2万+

C#基础篇(09)结构体(struct)与类(class)的详细区别

C#中结构体(struct)与类(class)的核心区别在于:结构体是值类型,直接存储数据,通常分配在栈上,适合小型临时对象;类是引用类型,通过指针访问堆内存,适合大型或长期存在的对象。关键差异包括内存管理方式(GC vs 栈分配)、赋值行为(复制值 vs 复制引用)、继承能力(类支持)、构造函数要求(结构体必须初始化所有字段)以及null值处理。结构体通常用于简单值类型(如坐标),而类更适合需要继承或多态的场景。设计时应考虑类型大小、语义需求(值/引用)、性能开销和生命周期管理等因素。

m0_55575697的博客 1609

C#结构体struct和类class的区别与使用场景

在我们开发程序中,功能实现可能没有问题,问题是如何将代码变得更优雅,优化程序运行。本文主要区别结构体与类的区别以及什么情况下使用结构体或类更为适合。结构是值类型,它在栈中分配空间;而类是引用类型,它在堆中分配空间,栈中保存的只是引用。所以比较小的数据时可以使用结构体来提升读取速度。而使用场景需要用到引用地址时就使用类。以上就是如何声明结构体使用,以及什么情况下使用结构体和类的全部内容。......

wolfman的博客 7260

核心C# - 类(class)和结构(struct)概述

考虑一个表示学生的类,该类可以包含学生的姓名、年龄和成绩数据,并提供获取和更新这些数据的方法。通过类,我们可以实例化具体的学生对象,每个对象都可以使用相同的模板,但具有自己独特的姓名、年龄和成绩信息。在实际应用中,类比结构更为常见,因为类支持更多的功能,如继承。结构通常用于表示较小的数据结构,以提高性能,因为在栈上存储值类型可以避免垃圾收集的开销。在面向对象编程中,类和结构都扮演着创建对象的模板的角色。同样考虑表示学生的结构,它具有相似的数据和操作,但是由于是值类型,它们的实例通常更轻量级。

江江的博客 618

C#类与结构体的区别

C#基础知识,学习笔记,整理总结

qq_44618510的博客 1323

c# 结构体与类区别

性能不同:由于结构体的实例被分配在栈上,所以在一些情况下,使用结构体比使用类更高效,比如在大量创建小对象时。但是,结构体也有一些限制,比如它的大小不能超过 16KB。针对默认构造函数的处理不同:结构体默认有一个无参的构造函数,而类如果没有显式定义构造函数,就会默认有一个无参的构造函数。内存分配方式不同:结构体是值类型,它的实例被分配在栈上,而类是引用类型,它的实例被分配在堆上。赋值方式不同:结构体赋值时是按值传递,即会复制一份,而类赋值时是按引用传递,即会复制一个引用。关键字定义,而类使用。

無限進步的全棧遊戲開發的博客 2098

C#——类与结构

在未学习面向对象语言时,我常常将类比作一种结构体,其实类与结构体也确实很相似,类用来做函数的集合,结构用来做变量的集合,接下来将从几个角度刨析类与结构的不同。

weixin_46146281的博客 1316

c#中struct和class的区别

1.不能显示定义无参数的构造函数,因为编译器会自动提供一个默认构造函数,把所有字段初始化为默认值(如int初始化为0,string初始化为null)struct是值类型,存储在栈上,当进行赋值时,会进行值拷贝,即创造一个新副本,适用于轻量级的数据结构,如点,矩形,日期等。class是引用类型,存储在堆上,当进行赋值时,只是复制引用而不是对象本身,适用于复杂的数据结构,如用户,订单等。2.如果没有定义任何构造函数,编译器会提供一个默认构造函数,将所有字段初始化为默认值。1.可以显式定义无参数的默认构造函数。

weixin_74353267的博客 423
上一篇: 深入理解 C# 中的值类型与引用类型
下一篇: 深入理解 C# 中 new 关键字的三重核心语义
bugcome_com
博客等级 码龄3年 32粉丝 131原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bugcome_com

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值