C#的record关键字如何定义不可变类型?有什么优势?

煙雲
发布: 2025-08-24 08:33:01
原创
540人浏览过
record关键字定义不可变类型,简化数据模型创建;其默认值语义、非破坏性修改(with表达式)和自动实现Equals/GetHashCode提升代码安全与可维护性;适用于DTO、值对象、配置等场景,确保数据不可变,避免并发bug,增强线程安全性。

c#的record关键字如何定义不可变类型?有什么优势?

C#的

record
登录后复制
关键字提供了一种简洁而强大的方式来定义不可变类型,其核心在于默认的非破坏性修改和值语义。这大大简化了数据模型的创建,提升了代码的清晰度和线程安全性,并且在处理数据传输对象(DTO)或领域模型时尤其有用,因为它能确保数据一旦创建就不会被意外修改,从而避免了许多潜在的bug。

public record Product(int Id, string Name, decimal Price);

上面的代码就定义了一个不可变的

Product
登录后复制
记录类型。
record
登录后复制
类型默认将其主构造函数参数对应的属性声明为
init
登录后复制
-only属性。这意味着这些属性只能在对象初始化时(包括通过
with
登录后复制
表达式创建新对象时)赋值,之后就不能再修改了。

// 创建一个Product实例
var p1 = new Product(1, "Laptop", 1200m);

// 尝试修改属性会报错,因为Name是init-only属性
// p1.Name = "Desktop"; // 编译错误:Init-only property or indexer 'Product.Name' can only be assigned in an object initializer, or on 'this' or 'base' in an instance constructor or an 'init' accessor.

// 使用with表达式进行非破坏性修改,创建一个新的record实例
var p2 = p1 with { Price = 1300m };

Console.WriteLine(p1); // Output: Product { Id = 1, Name = Laptop, Price = 1200 }
Console.WriteLine(p2); // Output: Product { Id = 1, Name = Laptop, Price = 1300 }
Console.WriteLine(ReferenceEquals(p1, p2)); // Output: False (它们是不同的对象)
登录后复制

通过

with
登录后复制
表达式,我们可以在不改变原对象的情况下,创建一个带有部分属性更新的新对象。这种“非破坏性修改”是
record
登录后复制
实现不可变性的关键机制之一。

为什么不可变类型在现代软件开发中如此重要?

在多线程和分布式系统日益普及的今天,可变状态是滋生bug的温床。我个人觉得,很多难以复现的并发问题,追根溯源都与某个共享的可变对象在不恰当的时机被修改有关。不可变类型从根本上消除了这种风险,因为它们一旦创建就不能被修改。这意味着你不需要担心一个对象在某个地方被意外更改,从而简化了并发编程,减少了锁的使用。

此外,不可变性极大地提升了代码的可预测性。当你在程序的任何地方传递一个不可变对象时,你都可以确信它的状态不会在不经意间发生变化。这使得调试变得容易得多,因为你不需要去追踪一个对象在不同方法调用中可能产生的各种副作用。在函数式编程范式中,不可变性更是基石,它鼓励我们编写无副作用的纯函数,让代码更易于理解、测试和维护。从长远来看,这种心智负担的减轻,远比多创建几个对象带来的微小性能开销更值得。

阿里云-虚拟数字人
阿里云-虚拟数字人

阿里云-虚拟数字人是什么? ...

阿里云-虚拟数字人 2
查看详情 阿里云-虚拟数字人

record
登录后复制
类型与传统类的不可变实现有何不同?

传统的C#类要实现不可变性,通常需要手动做很多工作。比如,你需要将所有属性设置为

get; init;
登录后复制
get; private set;
登录后复制
(然后只在构造函数中赋值),并且如果想实现值语义的相等性,还得手动重写
Equals
登录后复制
GetHashCode
登录后复制
方法。这不仅繁琐,而且容易出错。

record
登录后复制
类型则省去了大量这样的样板代码。它默认就为所有属性提供了
init
登录后复制
访问器,这意味着它们只能在对象初始化时赋值。更重要的是,
record
登录后复制
类型自动实现了基于值的相等性比较 (
Equals
登录后复制
GetHashCode
登录后复制
),以及一个美观的
ToString
登录后复制
方法。这些在类中都需要我们手动重写,而且很容易出错。尤其是当你的类型有很多属性时,手动实现这些方法简直是地狱。那个
with
登录后复制
表达式,更是提供了一种优雅且类型安全的方式来“修改”对象,实际上是创建了一个带有部分更改的新对象,这在处理数据流时简直是神器,让数据转换变得异常简洁。

record
登录后复制
类型在实际项目中有哪些典型的应用场景?

record
登录后复制
类型在很多场景下都能发光发热,特别是在需要处理大量数据或状态的系统中。最常见的可能就是作为DTOs,也就是数据传输对象。当你需要从数据库读取数据,或者通过API发送数据时,一个不可变的
record
登录后复制
能确保数据在传输过程中不会被意外篡改,提供了一种清晰的数据契约。

在领域驱动设计(DDD)中,它非常适合定义值对象,比如一个

Address
登录后复制
Money
登录后复制
DateRange
登录后复制
对象,它们由其属性值来定义其相等性,并且一旦创建就不应再改变。配置对象也是一个很好的例子,一旦加载,应用程序的配置就不应该再改变,
record
登录后复制
可以很好地保证这一点。甚至在一些前端框架(比如Blazor)的状态管理中,
record
登录后复制
也能简化状态更新的逻辑,因为每次更新都产生新状态,便于追踪和调试,尤其是在实现类似Redux的单向数据流模式时,
record
登录后复制
的不可变特性和
with
登录后复制
表达式都能带来极大的便利。它让我们的数据模型更加健壮,也让代码逻辑更加清晰。

以上就是C#的record关键字如何定义不可变类型?有什么优势?的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号