最近升级专案到大统一 .NET 5 并使用 C#9 语法尝试改写套件,发现以前觉得 record 只是简单属性 POCO 的简化语法糖的认知是错误。安全
另外由于 POCO 属于需定义口语词,这边在本文定义简单属性 POCO
为 public class 类别 {public string ID{get;set}/*略*/}
只有属性的简单类别代码app
一. rocord 的确底层是 class,但,不是单纯简单属性 POCO class
能够看 IL Spy 反编译程序码,发现系统帮咱们作了不少事
框架
二. 预设
生成的是属性是 {get;init;}
不是 {get;set;}
,这表明设定值
时间点在 constructor(建构式)
,延伸产生immutable(不可变)
特性,也表明 record 预设为thread-safe(线程安全)
,由于都是取得同样的值。ide
因此当你使用 Dapper 相似框架查询完 POCO 资料,想作修改属性时会报 CS8852 没法修改错误。
测试
三. 预设比较
逻辑改变
能够看TimCorey写的例子,能够看到预设 class 跟 record 的 == 差别,线上测试连结.net
public class Program { public static void Main() { var record1Obj1 = new record1(FirstName: "Lin", LastName: "WeiHan"); var record1Obj2 = new record1(FirstName: "Lin", LastName: "WeiHan"); Console.WriteLine(record1Obj1 == record1Obj2);//true var class1Obj1 = new Class1() { FirstName = "Lin", LastName = "WeiHan" }; var class2Obj2 = new Class1() { FirstName = "Lin", LastName = "WeiHan" }; Console.WriteLine(class1Obj1 == class2Obj2);//false } } public record record1(string FirstName,string LastName); public class Class1 { public string FirstName {get;init;} public string LastName{get;init;} }
由于 record override ==
跟 Equals
,认为只要是同一个 record 类型,而且属性值都同样
,系统就会认定为true
,也就是俗称的structural equality
,能够看 IL Spy 反编译代码线程
public virtual bool Equals(record2? other) { return (object)other != null && EqualityContract == other!.EqualityContract && EqualityComparer<string>.Default.Equals(FirstName, other!.FirstName) && EqualityComparer<string>.Default.Equals(LastName, other!.LastName); }
跟 object class 预设会去取得 RuntimeHelpers.GetHashCode
Handle 逻辑不相同。code
四. GetHashCode也作了相似逻辑,因此属性值同样,HashCode会获得同样的值
,线上测试连结
IL Spy 反编译代码图片
public override int GetHashCode() { return (EqualityComparer<Type>.Default.GetHashCode(EqualityContract) * -1521134295 + EqualityComparer<string>.Default.GetHashCode(FirstName)) * -1521134295 + EqualityComparer<string>.Default.GetHashCode(LastName); }
五. 注意不能把 record 看成必定是 immutable(不可变)
,缘由在微软没有限制
如下写法...get
public record record2 { public string FirstName {get;set;} public string LastName{get;set;} }
准许修改 {get;init;}
为 {get;set}
,将会致使 immutable 跟 thread-safe 特性消失
六. record 会帮忙生成可读性好的 ToString 实做
如下图片为比较通常 class 跟 record 生成的 ToString 差异
七. record 帮忙生成 extend IEquatable<类别>
,并实做强型别public virtual bool Equals(Record1? other)
这表明能够避免本来public override bool Equals(object? obj)
须要先 unboxing 再 boxing 的效能损耗
问题
阅读资料: