使用带init访问器的class与record有何差异?
带init访问器的class与record的核心区别
你写的这两段代码里,Student(class)和Student2(record)都用了init访问器,初始化后属性确实都没法修改,但两者的核心差异体现在设计语义和自动生成的功能上:
先贴出你的代码:
class Student { public int Id { get; init; } public string? Name { get; init; } } record Student2 { public int Id { get; init; } public string? Name { get; init; } }
具体区别如下:
- 语义本质不同:record是值语义类型,默认比较的是实例的属性值;class是引用语义类型,默认比较的是内存地址。比如两个
Student实例的Id和Name完全一样,student1 == student2会返回false,因为它们是不同的对象;但两个Student2实例做同样的比较会返回true,因为record默认按属性值判断相等。 - 自动生成的实用成员差异:record会自动帮你生成一堆常用方法,不用自己写:
- 重写的
Equals方法和IEquatable<T>实现,专门处理值相等判断 - 重写的
GetHashCode,保证属性相同的实例哈希码一致 - 格式化的
ToString,输出类似Student2 { Id = 1, Name = "张三" }的字符串,方便调试 - 解构方法,支持
var (id, name) = student2直接提取属性值 With表达式,比如var updatedStudent = student2 with { Name = "李四" },快速创建仅修改部分属性的新不可变实例
而class不会自动生成任何这些成员,所有相等判断、哈希码、ToString都得自己手动实现。
- 重写的
- 继承特性不同:record支持继承,子类record会自动继承父类的相等逻辑、ToString等行为;class的继承就是普通的引用类型继承,没有这些语义层面的自动继承特性。
- 不可变场景适配性:虽然两者都通过
init实现了属性不可变,但record的设计初衷就是作为不可变数据载体,配合With表达式能更便捷地处理不可变数据的更新;class的init只是限制了属性的修改时机,本质还是引用类型,更多用于面向对象的行为封装,而非纯数据承载。
内容的提问来源于stack exchange,提问作者Steve
相关产品推荐
相关产品推荐

