一晃距C# 9
发布已经4年了,对于record
关键字想必大家都不陌生了,不过呢发现还是有很多同学不屑于使用这个语法糖
,确实,本质上 record 就是 class 的封装,能用 record 书写的类,那100%都是可以自己手撸出来的,但是呢有没有考虑 别人可能一分钟写好的代码你可能会需要数分钟才能完成。
下面我简略聊一聊 record 的好处和最佳场景:
1. 简化语法
我们只需要一行代码就可以定义完成,这个是最直观节省编码的方式,我们不需要编写一堆枯燥的get;set; 也不需要编写构造函数等样板代码:
public record Person(string FirstName, string LastName);
那么有同学会有疑问,如果Person有很多的属性咋整,不就意味着主构造函数会很冗长,其实这个和封装传参的方式是一样的,我们可以把同质的属性封装成其他的record或者class,比如:
public record ExtraInfomation(string Address,string Email,int Age);
public record Person(string FirstName, string LastName, ExtraInfomation ExtraInfo);
2. 自动生成一些对我们有用的成员函数
- 构造函数:根据定义的属性自动生成构造函数。
- 属性:自动生成只读属性。
- Deconstruct 方法:用于解构记录对象,对于习惯写
TS
的小伙伴相当友好。 - Equals 和 GetHashCode 方法:基于属性值的相等性比较。
- ToString 方法:提供友好的字符串表示,对于调试输出特别友好。
3. 基于值的相等性语法
我们很多时候有这种需求就是比较一个类的所有属性来判断逻辑。如果使用 record 的话 我们只需要==
或者Equals
就能判断。
4. 非破坏性复制值
对于一个 class 的浅表复制,我们可能需要实现ICloneable
,亦或 new 一个对象逐个属性赋值,当然还有其他的方法,但是肯定是没有 record 来的这么简单直接,我们仅需要一个with
关键字就可以了:
public record Person(string FirstName, string LastName, int Age);
var person1 = new Person("vip", "wan", 18);
var person2 = person1 with { Age = 30 };
Console.WriteLine(person1); // 输出: Person { FirstName = vip, LastName = wan, Age = 18 }
Console.WriteLine(person2); // 输出: Person { FirstName = vip, LastName = wan, Age = 30 }
5. 解构的支持
record 类型自动生成 Deconstruct 方法,允许你轻松地解构 record 对象,对于全栈的同学书写就是手到擒来!
var person = new Person("vip", "wan", 18);
var (firstName, lastName, age) = person;
Console.WriteLine(firstName); // 输出: vip
Console.WriteLine(lastName); // 输出: wan
Console.WriteLine(age); // 输出: 18
6. 结合模式匹配
record 类型与模式匹配功能很好地集成在一起,使得在模式匹配中使用 record 对象更加方便。
public record Person(string UserName, int Age);
public string GetPersonInfo(Person person) => person switch
{
{ Age: < 18 } => "Minor",
{ Age: >= 18 } => "Adult",
_ => "Unknown"
};
7. 填充既有类
因此我们如果需要对既有的 class 支持到 record 的特性我们只需要在class前加上 record 即可。
public record class User {
public string UserName{ get; set;}
public int Age { get; set;}
}
var user1 = new User { UserName = "vipwan" , Age = 18};
var user2 = user1 with { };
var user3 = user1 with { Age = 30 };
user1 == user2 // true;
user3.ToString() // "User { Name = vipwan, Age = 30 }"
总结
使用 record 类型的主要好处包括简洁的语法、自动生成的成员、基于值的相等性、非破坏性复制、解构支持、继承支持和与模式匹配的良好集成。这些特性使得 record 类型非常适合用于不可变数据对象(DTO,VO等),提高了代码的可读性、可维护性和开发效率。