C# 9引入的Record类型是一种特殊的引用类型,主要用于存储不可变的数据载体,它在设计上和传统的Class有明显差异,也带来了很多独有的优势。Record的核心设计目标是简化数据类的编写,减少样板代码,同时提供更适合数据场景的特性。

Record类型的核心优势
1. 自动实现值相等性
传统的Class默认使用引用相等性,判断两个对象是否相等时比较的是引用地址,而Record默认实现值相等性,只要两个Record对象的所有属性值都相同,就会判定为相等。这不需要开发者手动重写Equals、GetHashCode方法,减少了重复代码。
2. 简洁的语法定义
Record支持位置参数语法,只需要一行代码就可以定义包含多个属性的数据载体,编译器会自动生成对应的属性、构造函数、解构方法等,比传统Class的定义方式简洁很多。
3. 内置不可变特性支持
Record默认的属性是init-only的,只能在对象初始化时赋值,之后无法修改,天然适合存储不可变数据,避免了意外修改数据带来的问题,也更符合函数式编程的思想。
4. 方便的复制修改能力
Record支持with表达式,可以快速创建一个和原有对象属性大部分相同,仅部分属性不同的新对象,不需要手动编写复制构造函数或者逐个赋值属性。
Record与Class的用法区别
定义方式差异
Class需要手动定义属性、构造函数,而Record可以用简洁的位置参数或者普通属性语法定义。下面是两者的定义示例:
// 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位置参数定义示例
public record PersonRecord(string Name, int Age);
// Record普通属性定义示例
public record PersonRecord2
{
public string Name { get; init; }
public int Age { get; init; }
}
相等性判断差异
Class的==和Equals默认比较引用地址,Record默认比较属性值。示例如下:
var class1 = new PersonClass("张三", 20);
var class2 = new PersonClass("张三", 20);
Console.WriteLine(class1 == class2); // 输出 False,引用不同
Console.WriteLine(class1.Equals(class2)); // 输出 False
var record1 = new PersonRecord("张三", 20);
var record2 = new PersonRecord("张三", 20);
Console.WriteLine(record1 == record2); // 输出 True,属性值相同
Console.WriteLine(record1.Equals(record2)); // 输出 True
属性修改方式差异
Class的属性如果是可读可写的,可以直接修改;Record的属性默认是init-only,不能直接修改,需要使用with表达式创建新对象。示例如下:
// Class修改属性
var personClass = new PersonClass("张三", 20);
personClass.Age = 21; // 可以直接修改
// Record修改属性
var personRecord = new PersonRecord("张三", 20);
// personRecord.Age = 21; 这行会编译报错,属性不可修改
var newPersonRecord = personRecord with { Age = 21 }; // 创建新对象,Age改为21
Console.WriteLine(newPersonRecord.Name); // 输出 张三
Console.WriteLine(newPersonRecord.Age); // 输出 21
继承特性差异
Class支持任意继承,Record也支持继承,但是Record的继承有一些限制:Record只能继承自其他Record,不能继承自Class,也不能被Class继承。示例如下:
// Record继承示例
public record StudentRecord(string Name, int Age, string School) : PersonRecord(Name, Age);
var student = new StudentRecord("李四", 18, "XX中学");
var person = (PersonRecord)student; // 可以向上转型
Console.WriteLine(person.Name); // 输出 李四
适用场景选择
如果场景是存储不可变的数据载体,需要频繁比较属性值是否相同,或者需要快速复制修改对象,优先选择Record。如果是需要频繁修改属性,或者需要复杂的继承层次、实现更多的业务逻辑方法,优先选择Class。
| 对比维度 | Record | Class |
|---|---|---|
| 相等性默认实现 | 值相等性 | 引用相等性 |
| 属性可变性 | 默认init-only,不可变 | 可按需定义为可读可写 |
| 定义简洁度 | 高,支持位置参数 | 低,需要手动编写较多代码 |
| 复制修改支持 | 原生支持with表达式 | 需要手动实现 |
| 继承限制 | 只能继承Record | 可继承Class,可被Class继承 |