【C#】C# 中的 `init`、`readonly` 和 `const` 有什么区别?

⚙️ C# 中的 initreadonlyconst 有什么区别?

在 C# 编程中,我们经常需要定义 不可变(immutable) 的数据。那么该用 constreadonly,还是 init 呢?这三者虽然都可用于定义不可变成员,但它们的应用场景和语法限制却大不相同。本文将通过对比和示例,帮助你理清它们的区别与用法。


📌 1. 简要对比表

特性 const readonly init
赋值时机 定义时 构造函数或定义时 初始化时(对象构造期间)
是否编译期常量 ✅ 是 ❌ 不是 ❌ 不是
可用于字段 ✅(属性)
可用于属性 ✅(支持 get-only) ✅(支持 set-only-once)
赋值位置 定义时 构造函数、字段初始化 对象初始化表达式 {}
常用于 全局常量、数学值 构造后不变的实例字段 构造后不变但支持对象初始化的属性

🧱 2. const ------ 编译期常量

csharp 复制代码
public class Constants
{
    public const double Pi = 3.14159;
}

✅ 特点:

  • 必须在定义时赋值
  • 编译为常量值,直接嵌入调用代码中
  • 只能修饰 基本类型string 等编译期常量

⚠️ 注意:

  • 修改 const 值需 重新编译所有引用它的程序集,否则可能仍然使用旧值!

🧱 3. readonly ------ 运行期常量(构造后不可变)

csharp 复制代码
public class Config
{
    public readonly string Version;

    public Config(string version)
    {
        Version = version;
    }
}

✅ 特点:

  • 可以在定义时或构造函数中赋值
  • 适合依赖运行期值(如时间戳、GUID、配置文件)
csharp 复制代码
public readonly DateTime StartTime = DateTime.Now;

⚠️ 注意:

  • readonly 不能在构造函数外被修改
  • 可用于字段,常配合 private 修饰

🧱 4. init ------ 初始化器赋值(C# 9 引入)

csharp 复制代码
public class Person
{
    public string Name { get; init; }
    public int Age { get; init; }
}

✅ 特点:

  • 支持对象初始化表达式语法 {} 中赋值
  • 一旦对象构造完成,属性就不可更改
csharp 复制代码
var p = new Person { Name = "Alice", Age = 30 };
// p.Age = 31; // ❌ 编译错误

👍 优势:

  • 与面向对象封装天然适配
  • 保留不可变性同时支持初始化灵活性

🚩 5. 使用建议总结

使用场景 推荐关键词 理由
编译期不会变化的值(如 Pi) const 编译时已确定,性能更优
运行期动态初始化的字段 readonly 构造函数中灵活赋值,构造后不可变
想使用初始化表达式设定属性值 init 可读性强,避免创建多个构造函数
想实现不可变对象(immutable) init + get 提供只读接口,同时允许构造期间初始化

✅ 总结

关键词 可变性 赋值时机 使用场景
const 永远不可变 定义时 编译期常量
readonly 构造后不可变 构造函数或定义时 运行期常量,依赖构造动态赋值
init 构造后不可变 对象初始化表达式期间 封装属性,构造时赋值灵活

选择合适的不可变策略,可以帮助你写出更安全、清晰、易维护的代码!


📬 你更常用哪种不可变成员定义方式?欢迎评论区分享你的使用经验!

如果你觉得这篇文章有帮助,别忘了点赞、收藏和关注我~ 🚀

相关推荐
小羊没烦恼!2 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
神仙别闹2 天前
基于C#+MySQL实现(WinForm)个人聊天室软件
c#
伞伞悦读2 天前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__
开发语言·python
C语言小火车2 天前
C/C++ 为什么需要编译器?
开发语言·c++
霍霍的袁2 天前
【C++】map 和 set 的使用 | 从用法到底层
开发语言·c++·学习·visual studio
kybs19912 天前
全球灾害数据分析可视化 毕业设计-附源码66794
vue.js·spring boot·mysql·安全·django·c#·asp.net
孙启超2 天前
【AI开发之Rust】第 11 课:智能指针与内部可变性
开发语言·后端·rust
此生决int2 天前
深入理解C++系列(20)——C++11(下)
开发语言·c++
CoderYanger2 天前
A.每日一题:835. 图像重叠
java·开发语言·程序人生·leetcode·面试·职场和发展·学习方法
伞伞悦读2 天前
【第37期】Python JSON 与配置详解:序列化、反序列化、嵌套结构和配置文件
开发语言·python·json