C# 9 record 並不是簡單屬性 POCO 的語法糖

C# 9 record 並不是簡單屬性 POCO 的語法糖

最近升級專案到大統一 .NET 5 並使用 C#9 語法嘗試改寫套件,發現以前覺得 record 只是簡單屬性 POCO 的簡化語法糖的認知是錯誤。安全

另外由於 POCO 屬於需定義口語詞,這邊在本文定義簡單屬性 POCOpublic 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 的效能損耗問題

閱讀資料:

相關文章
相關標籤/搜索