C#的record类型和class类型有何不同?

来源:IT编程作者:缓存小熊猫头衔:程序员
导读:本期聚焦于小伙伴创作的《C#的record类型和class类型有何不同?》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C#的record类型和class类型有何不同?》有用,将其分享出去将是对创作者最好的鼓励。

C# 9.0引入了record类型,它和传统的class类型同属引用类型,但在设计理念和特性上有诸多不同,下面从多个维度展开对比说明。

C#的record类型和class类型有何不同?

基础定义差异

class是C#传统的引用类型,定义时需要显式声明构造函数、属性等成员,而record提供了更简洁的语法,支持使用位置参数快速定义。

首先是class的典型定义方式:

// class类型定义
public class PersonClass
{
    public string Name { get; set; }
    public int Age { get; set; }

    public PersonClass(string name, int age)
    {
        Name = name;
        Age = age;
    }
}

对应的record定义可以非常简洁:

// record类型定义,使用位置参数自动生成属性、构造函数等
public record PersonRecord(string Name, int Age);

相等性判断逻辑不同

这是两者最核心的差异之一。class默认使用引用相等性,即两个对象只有指向同一个堆内存地址时才判定为相等;而record默认使用值相等性,只要两个对象的所有属性值都相同,就判定为相等。

我们可以通过以下代码验证这个差异:

PersonClass class1 = new PersonClass("张三", 20);
PersonClass class2 = new PersonClass("张三", 20);
// class的引用相等性判断,结果为false
Console.WriteLine(class1 == class2); 

PersonRecord record1 = new PersonRecord("张三", 20);
PersonRecord record2 = new PersonRecord("张三", 20);
// record的值相等性判断,结果为true
Console.WriteLine(record1 == record2); 

如果需要让class也支持值相等性,需要手动重写Equals方法、GetHashCode方法,还要重载==!=运算符,实现成本远高于record。

不可变性支持差异

record天然支持不可变性,默认生成的属性是只读的,初始化后无法修改属性值;而class的属性默认是可写的,除非显式将set访问器设为private或者只保留get访问器。

尝试修改record的属性会直接编译报错:

PersonRecord record = new PersonRecord("李四", 25);
// 编译错误:属性是只读的,无法赋值
record.Name = "王五"; 

如果需要在record中修改属性,可以使用with表达式生成新的record实例,原实例不会被修改:

PersonRecord record1 = new PersonRecord("李四", 25);
// 生成新的record实例,修改Name属性
PersonRecord record2 = record1 with { Name = "王五" };
Console.WriteLine(record1.Name); // 输出 李四,原实例未修改
Console.WriteLine(record2.Name); // 输出 王五

而class要修改属性则非常直接,不需要生成新实例:

PersonClass person = new PersonClass("李四", 25);
person.Name = "王五"; // 直接修改属性,编译通过
Console.WriteLine(person.Name); // 输出 王五

内置方法差异

record会自动生成一些class默认没有的方法:

  • ToString方法:record重写了ToString,会输出所有属性名和对应的值,方便调试;class的默认ToString输出的是类型全名。
  • Deconstruct方法:record自动支持解构,可以直接将属性拆分到多个变量中。

以下是相关用法的代码示例:

PersonRecord record = new PersonRecord("赵六", 30);
// record的ToString输出:PersonRecord { Name = 赵六, Age = 30 }
Console.WriteLine(record.ToString());

// record的解构用法
var (name, age) = record;
Console.WriteLine($"姓名:{name},年龄:{age}"); // 输出 姓名:赵六,年龄:30

PersonClass person = new PersonClass("赵六", 30);
// class的ToString输出:PersonClass(实际会带命名空间)
Console.WriteLine(person.ToString());

适用场景对比

根据两者的特性,适用场景也有明显区分:

类型适用场景
class需要灵活控制对象行为、需要频繁修改属性值、需要继承扩展复杂逻辑的场景,比如业务实体、服务类、包含复杂方法的对象等。
record只需要承载数据、不需要修改属性值、需要值相等性判断的场景,比如DTO、配置模型、临时数据载体、不可变数据对象等。

继承特性差异

record支持继承,但是只能继承自其他record,不能继承自class;class可以继承自其他class,也可以实现接口,record同样可以实现接口。

// record的继承示例
public record AnimalRecord(string Name);
public record DogRecord(string Name, string Breed) : AnimalRecord(Name);

// record实现接口示例
public interface IHasId
{
    int Id { get; }
}
public record UserRecord(int Id, string Name) : IHasId;

需要注意的是,record的继承场景下,值相等性判断会同时比较基类和派生类的所有属性,只有全部属性值都相同才会判定为相等。

C#record类型class类型值相等性不可变性修改时间:2026-07-23 14:30:30

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。