【C#/.NET】record介紹

?目錄


什么是record?

使用record

record解構(gòu)

record原理

結(jié)論


什么是record?

record是.NET 5中的一種新特性,可以看作是一種概念上不可變的類。records可以幫助我們在C#中更容易地處理數(shù)據(jù),同時提供了重要的功能,如對象相等性、hashcode和解構(gòu)。

與類不同,records具有值語義。也就是說,當(dāng)比較兩個records的實(shí)例時,比較的是這些實(shí)例的屬性而非引用。這意味著,如果兩個records的屬性值相同,它們就是相等的。

record也可以簡化需要類似于Dto的數(shù)據(jù)結(jié)構(gòu)容器的定義。

使用record

Person p1 =new("小明","南山","11@outlook.com");

Person p2 =new("小明","南山","11@outlook.com");

Console.WriteLine(p1 == p2);publicrecord Person(stringName,stringAddress,stringEmail);

像定義一個類一樣,public class Person,只是將class關(guān)鍵字替換成record關(guān)鍵字。然后屬性是用括號來定義。

默認(rèn)的record聲明是class,如果想聲明一個struct

publicrecordstructPerson(stringName,stringAddress,stringEmail);

record是不可變的類型,括號中聲明的屬性在構(gòu)造之后不可變更??梢允褂?=按屬性的值進(jìn)行比較??梢灾苯幼鳛閔ash的key以及結(jié)構(gòu)。

record可以像普通類一樣擴(kuò)展可變更的屬性和自定義的方法,語法如下

publicrecord Person(stringName,stringAddress,string Email)

{

? ? publicrequiredstringPhoneNumber {get;set; }

? ? publicstaticIEnumerable GetAll()

? ? {

? ? ? ? yieldreturnnewPerson("張三","123 Main St","john@example.com") { PhoneNumber ="123456789"};

? ? ? ? yieldreturnnewPerson("李四","456 Elm St","jane@example.com") { PhoneNumber ="123456789" };

? ? ? ? yieldreturnnewPerson("王二","789 Oak St","bob@example.com") { PhoneNumber ="123456789" }; ;

? ? }

? ? publicstringGetDisplayName() => $"{Name} ({Email})";

};

record解構(gòu)

record可以通過解構(gòu),將對象解構(gòu)為元組,方便一次性獲取record中的屬性值,

Person p1 =new("小明","南山","11@outlook.com") ;var(name,address,email) = p1 ;

record原理

record的原理是編譯器提供支持,上述Person定義反編譯結(jié)果如下

publicclassPerson : IEquatable{

? ? [CompilerGenerated]

? ? protectedvirtual Type EqualityContract

? ? {

? ? ? ? [CompilerGenerated]

? ? ? ? get? ? ? ? {

? ? ? ? ? ? returntypeof(Person);

? ? ? ? }

? ? }

? ? publicstringName {get;set/*init*/; }

? ? publicstringAddress {get;set/*init*/; }

? ? publicstringEmail {get;set/*init*/; }

? ? publicPerson(stringName,stringAddress,string Email)

? ? {

? ? ? ? this.Name = Name;

? ? ? ? this.Address = Address;

? ? ? ? this.Email = Email;

? ? ? ? base..ctor();

? ? }

? ? [CompilerGenerated]

? ? publicoverridestring ToString()

? ? {

? ? ? ? StringBuilder stringBuilder =new StringBuilder();

? ? ? ? stringBuilder.Append("Person");

? ? ? ? stringBuilder.Append(" { ");

? ? ? ? if (PrintMembers(stringBuilder))

? ? ? ? {

? ? ? ? ? ? stringBuilder.Append('');

? ? ? ? }

? ? ? ? stringBuilder.Append('}');

? ? ? ? return stringBuilder.ToString();

? ? }

? ? [CompilerGenerated]

? ? protectedvirtualbool PrintMembers(StringBuilder builder)

? ? {

? ? ? ? RuntimeHelpers.EnsureSufficientExecutionStack();

? ? ? ? builder.Append("Name = ");

? ? ? ? builder.Append((object?)Name);

? ? ? ? builder.Append(", Address = ");

? ? ? ? builder.Append((object?)Address);

? ? ? ? builder.Append(", Email = ");

? ? ? ? builder.Append((object?)Email);

? ? ? ? returntrue;

? ? }

? ? [CompilerGenerated]

? ? publicstaticbooloperator!=(Person? left, Person? right)

? ? {

? ? ? ? return!(left == right);

? ? }

? ? [CompilerGenerated]

? ? publicstaticbooloperator==(Person? left, Person? right)

? ? {

? ? ? ? return(object)left == right || (left?.Equals(right) ??false);

? ? }

? ? [CompilerGenerated]

? ? publicoverrideint GetHashCode()

? ? {

? ? ? ? return((EqualityComparer.Default.GetHashCode(EqualityContract) * -1521134295+ EqualityComparer.Default.GetHashCode(Name)) * -1521134295+ EqualityComparer.Default.GetHashCode(Address)) * -1521134295+ EqualityComparer.Default.GetHashCode(Email);

? ? }

? ? [CompilerGenerated]

? ? publicoverrideboolEquals(object? obj)

? ? {

? ? ? ? returnEquals(objas Person);

? ? }

? ? [CompilerGenerated]

? ? publicvirtualboolEquals(Person? other)

? ? {

? ? ? ? return(object)this== other || ((object)other !=null&& EqualityContract == other.EqualityContract && EqualityComparer.Default.Equals(Name, other.Name) && EqualityComparer.Default.Equals(Address, other.Address) && EqualityComparer.Default.Equals(Email, other.Email));

? ? }

? ? [CompilerGenerated]

? ? protected Person(Person original)

? ? {

? ? ? ? Name = original.Name;

? ? ? ? Address = original.Address;

? ? ? ? Email = original.Email;

? ? }

? ? [CompilerGenerated]

? ? publicvoidDeconstruct(outstringName,outstringAddress,outstring Email)

? ? {

? ? ? ? Name =this.Name;

? ? ? ? Address =this.Address;

? ? ? ? Email =this.Email;

? ? }

}

?可以看到,編譯器給使用了record關(guān)鍵字的定義生成了對應(yīng)的屬性和構(gòu)造函數(shù),并且重寫了ToString(),GetHashCode,Equals還有一個解構(gòu)函數(shù)和!=和==運(yùn)算符。其實(shí)看到這里就明白了,為什么record可以提供值比較,解構(gòu),hash等。

不可變性是因?yàn)閞ecord的屬性是使用了init關(guān)鍵字而不是set,這樣子如果對record的對象屬性賦值,編譯器會報錯。

值相等性是重定義了!=和==運(yùn)算符

hash是因?yàn)橹貙懥薌etHashCode,Equals

解構(gòu)是定義了Deconstruct方法

結(jié)論

我們介紹了.NET 5中引入的record類型及其優(yōu)點(diǎn)。但對于許多數(shù)據(jù)對象的簡單情況,如值對象和DTO,推薦使用record類型。雖然record可以定義可變更的屬性和添加方法,不過這樣子有點(diǎn)違背了record的初衷。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容