2020年11月24日星期二

C# 9 record 并非简单属性 POCO 的语法糖

C# 9 record 并非简单属性 POCO 的语法糖

最近升级专案到大统一 .NET 5 并使用 C#9 语法尝试改写套件,发现之前以为 record 只是简单属性 POCO 的简化语法糖的认知是错误。

另外因为 POCO 属于需定义口语词,这边在本文定义简单属性 POCOpublic class 类别 {public string ID{get;set}/*略*/} 只有属性的简单类别代码

一. rocord 的确底层是 class,但,不是单纯简单属性 POCO class
可以看 IL Spy 反编译程序码,发现系统帮我们做了很多事

二. 预设生成的是属性是 {get;init;} 不是 {get;set;},这代表设定值时间点在 constructor(建构式),延伸产生immutable(不可变)特性,也代表 record 预设为thread-safe(线程安全),因为都是取得一样的值。

所以当你使用 Dapper 类似框架查询完 POCO 资料,想做修改属性时会报 CS8852 无法修改错误。

三. 预设比较逻辑改变
可以看TimCorey写的例子,可以看到预设 class 跟 record 的 == 差异,线上测试连结

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 逻辑不相同。

四. 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(不可变),原因在微软没有限制以下写法...

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 的效能损耗问题

阅读资料:

  • https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9








原文转载:http://www.shaoqun.com/a/492947.html

cima:https://www.ikjzd.com/w/1372

吉祥邮:https://www.ikjzd.com/w/1565

bap:https://www.ikjzd.com/w/1492


C#9record并非简单属性POCO的语法糖最近升级专案到大统一.NET5并使用C#9语法尝试改写套件,发现之前以为record只是简单属性POCO的简化语法糖的认知是错误。另外因为POCO属于需定义口语词,这边在本文定义简单属性POCO为publicclass类别{publicstringID{get;set}/*略*/}只有属性的简单类别代码一.rocord的确底层是class,但,不是单纯
中转贸易:中转贸易
tradeindia:tradeindia
牛仔谷漂流开放时间?清远牛仔谷漂流几点开始?:牛仔谷漂流开放时间?清远牛仔谷漂流几点开始?
如何利用Product Targeting 提高你的亚马逊广告转化率?:如何利用Product Targeting 提高你的亚马逊广告转化率?
口述:闺蜜大胸撑破内衣 老公羡慕不已胸部大胸闺蜜:口述:闺蜜大胸撑破内衣 老公羡慕不已胸部大胸闺蜜

没有评论:

发表评论