当前位置: 首页 > news >正文

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

C# 中结构体(struct)与类(class)的详细区别

在 C# 中,结构体(struct)和类(class)都是用于创建自定义类型的构造,但它们有显著的区别,这些区别影响着它们的使用场景和性能表现。

1. 基本类型分类

  • 类(class)​​:引用类型(reference type)
  • 结构体(struct)​​:值类型(value type)

这是最根本的区别,由此衍生出许多其他差异。

2. 内存分配

  • ​:

    • 分配在堆(heap)上
    • 通过引用来访问
    • 由垃圾回收器(GC)管理内存
  • 结构体​:

    • 分配在栈(stack)上(通常情况)
    • 直接存储值本身
    • 超出作用域时立即释放
// 类示例
class MyClass { public int X; }// 结构体示例
struct MyStruct { public int X; }MyClass c = new MyClass(); // 在堆上分配
MyStruct s = new MyStruct(); // 在栈上分配(通常情况)

3. 默认值

  • ​:默认值为 null
  • 结构体​:不能为 null(除非使用可空类型),总是有默认值(各字段为默认值)
MyClass c; // c 为 null
MyStruct s; // s 已初始化,s.X == 0

4. 赋值行为

  • ​:赋值的是引用(两个变量指向同一对象)
  • 结构体​:赋值的是值的副本(创建新副本)
MyClass c1 = new MyClass { X = 1 };
MyClass c2 = c1; // c2 和 c1 指向同一对象
c2.X = 2; // c1.X 也变为 2MyStruct s1 = new MyStruct { X = 1 };
MyStruct s2 = s1; // 创建 s1 的副本
s2.X = 2; // s1.X 仍为 1

5. 继承

  • ​:

    • 支持单继承
    • 可以继承自另一个类
    • 可以实现多个接口
  • 结构体​:

    • 隐式继承自 System.ValueType
    • 不能继承自其他结构体或类
    • 可以实现接口
class BaseClass {}
class DerivedClass : BaseClass {} // 合法struct BaseStruct {}
// struct DerivedStruct : BaseStruct {} // 编译错误

6. 构造函数

  • ​:

    • 可以有无参构造函数
    • 如果没有定义构造函数,编译器会提供默认无参构造函数
  • 结构体​:

    • 总是有一个隐式的无参构造函数(即使定义了其他构造函数)
    • 不能自定义无参构造函数
    • 构造函数必须初始化所有字段
struct MyStruct
{public int X;public int Y;// 结构体构造函数必须初始化所有字段public MyStruct(int x, int y){X = x;Y = y;}// 不能定义无参构造函数// public MyStruct() { } // 编译错误
}

7. 性能考虑

  • ​:

    • 堆分配和垃圾回收可能带来性能开销
    • 适合大型对象或需要长期存在的对象
  • 结构体​:

    • 栈分配通常更快
    • 没有垃圾回收开销
    • 适合小型、短暂使用的对象
    • 频繁装箱/拆箱会降低性能

8. 适用场景

  • 使用类的情况​:

    • 需要继承
    • 对象标识重要(两个变量引用同一对象)
    • 对象较大
    • 对象生命周期较长
    • 需要多态行为
  • 使用结构体的情况​:

    • 表示简单的值类型(如坐标、颜色等)
    • 小型数据结构(通常小于16字节)
    • 不可变类型
    • 频繁创建和销毁的临时对象
    • 不需要多态行为

9. 其他区别

特性类(class)结构体(struct)
可以为 null否(除非可空类型)
可以包含析构函数
可以作为 lock 的目标
默认访问修饰符internalpublic
字段初始化允许不允许

10. 示例对比

// 类示例
public class PointClass
{public int X;public int Y;public PointClass(int x, int y){X = x;Y = y;}
}// 结构体示例
public struct PointStruct
{public int X;public int Y;public PointStruct(int x, int y){X = x;Y = y;}
}// 使用对比
PointClass pc1 = new PointClass(1, 2);
PointClass pc2 = pc1; // 复制引用
pc2.X = 3; // pc1.X 也变为 3PointStruct ps1 = new PointStruct(1, 2);
PointStruct ps2 = ps1; // 复制值
ps2.X = 3; // ps1.X 仍为 1

11. 可变性与不可变性

结构体通常更适合设计为不可变类型:

public readonly struct ImmutablePoint
{public readonly int X;public readonly int Y;public ImmutablePoint(int x, int y){X = x;Y = y;}
}

12. 装箱与拆箱

  • 结构体转换为 object 或接口类型时会发生装箱
  • 从 object 或接口类型转换回结构体会发生拆箱
  • 装箱/拆箱有性能开销,应尽量避免
MyStruct s = new MyStruct();
object boxed = s; // 装箱
MyStruct unboxed = (MyStruct)boxed; // 拆箱

总结

选择使用类还是结构体应基于以下考虑:

  1. 类型的大小(结构体应保持小型)
  2. 所需语义(值语义 vs 引用语义)
  3. 性能需求
  4. 是否需要继承或多态
  5. 生命周期管理需求

理解这些区别有助于在C#开发中做出更合理的设计决策,编写出更高效、更可靠的代码。

http://www.dtcms.com/a/271701.html

相关文章:

  • Vue响应式原理三:响应式依赖收集-类
  • 大模型的下半场:从工具到智能体的产业变革与2025突围之路
  • AI大模型:(二)4.2 文生图训练实践-真人写实生成
  • 8.2 文档预处理模块(二)
  • 学习笔记(31):matplotlib绘制简单图表-直方图
  • UNet改进(19):基于残差注意力模块Residual Attention的高效分割网络设计
  • 编译安装的Mysql5.7报“Couldn‘t find MySQL server (mysqld_safe)“的原因 笔记250709
  • 主流大模型Agent框架 AutoGPT详解
  • 软件互联网产品发版检查清单
  • WIndows 编程辅助技能:格式工厂的使用
  • Dify教程更改文件上传数量限制和大小限制
  • JVM 调优
  • 双指针-15.三数之和-力扣(LeetCode)
  • AI技术如何重塑你的工作与行业?——实战案例解析与效率提升路径
  • gdb调试工具
  • Lingo软件学习(一)好学爱学
  • DPDK graph图节点处理框架:模块化数据流计算的设计与实现
  • dify配置邮箱,密码重置以及邮箱邀请加入
  • 【Java】【字节面试】字符串中 出现次数最多的字符和 对应次数
  • HTML应用指南:利用GET请求获取全国山姆门店位置信息
  • 跨服务sqlplus连接oracle数据库
  • 如何卸载本机的node.js
  • 源码角度解析 --- HashMap 的 get 和 put 流程
  • 前端使用fetch-event-source实现AI对话
  • AI Agent:我的第一个Agent项目
  • 爬虫-数据解析
  • [C语言初阶]操作符
  • ZeroMQ 代理架构实现(Python 服务端 + C++ 代理 + C++ 客户端)
  • RabbitMQ 4.1.1-Local random exchange体验
  • 解决Ollama下载太慢问题