record 记录类型用来定义一个简单的、不可变(只读) 的数据结构,定义比较方便,常用于一些简单的数据传输场景。record 本质上就是定义一个class
类型(也可申明为record struct
结构体),因此语法上就是 类型申明+主构造函数的形式。
🚩 可以把 Record 看做是一个快速定义类(结构体)的语法糖,编译器会构建完整的类型。
- 构造函数中的参数会生成公共的只读属性,其他自动生成的内容还包括
Equals
、ToString
、解构赋值等。 - record 默认为
class
(可缺省),用record struct
则可申明为一个结构体的。 - record 类型可以继承另一个record类型,或接口,但不能继承其他普通
class
。 - 支持使用
with
语句创建非破坏性副本。
public record Car(string Width); //class public record struct User(string Name, int Age);//struct public record class Person(DateTime Birthday); //class void Main() { var u1 = new User("sam",122); var u2 = new User("sam",122); u1.Age = 1; //只读,不可修改 Console.WriteLine(u1 ==u2); //True Console.WriteLine(Object.ReferenceEquals(u1,u2)); //False var (name,_) = u1; //解构赋值 Console.WriteLine(name); //sam } public record Person2 //创建一个可更改的recored类型 { public string FirstName { get; set; } public string LastName { get; set; } };
通过查看编译后的代码来了解recored
的本质,下面是代码public record User(string Name, int Age)
编译后生成的代码(简化后),完整代码可查看在线 sharplab代码。
- 主构造函数中的参数都生成了只读属性,如果是
struct
结构体则属性是可读、可写的。 - 生成了
ToString()
方法,用stringBuilder 打印了所有字段名、字段值。 - 生成了相等比较的方法、相等运算符重载,及
GetHashCode()
,相等比较会比较字段值。 - 还生成了
Deconstruct
方法,用来支持解构赋值,var (name,age) = new User("sam",19);
。
public class User : IEquatable<User> { public string Name{get;init;} public int Age{get;init;} public User(string Name, int Age) { this.Name = Name; this.Age = Age; } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); //把所有字段名、值输出 return stringBuilder.ToString(); } public static bool operator !=(User left, User right) { return !(left == right); } public static bool operator ==(User left, User right) {...} public override int GetHashCode() {...} public virtual bool Equals(User other) {...} //支持解构赋值Deconstruct public void Deconstruct(out string Name, out int Age) { Name = this.Name; Age = this.Age; } }
record 申明可以用简化的语法(只有主构造函数,没有“身体”),也可以和class
一样自定义一些内部成员。如下面示例中,自定义实现了ToString
方法,则编译器就不会再生成该方法了,同时这里加了密封sealed
标记,子类也就不能重写了。
void Main() { var u = new User("John", 25); Console.WriteLine(u.ToString()); u.SayHi(); } public record User(string Name, int Age) { public sealed override string ToString() => $"{Name} {Age}"; public void SayHi() => Console.WriteLine($"Hi {Name}"); }