欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C# 9 新特性——record的相關(guān)總結(jié)

 更新時(shí)間:2021年02月01日 09:10:26   作者:WeihanLi  
這篇文章主要介紹了C# 9 新特性——record的相關(guān)總結(jié),幫助大家更好的理解和學(xué)習(xí)使用c# 9的新特性,感興趣的朋友可以了解下

Intro

C# 9 中引入了 record,record 是一個(gè)特殊類,用它來實(shí)現(xiàn) model 在有些情況下會(huì)非常的好用

Sample

record RecordPerson
{
 public string Name { get; init; }

 public int Age { get; init; }
}

record RecordPerson2(string Name, int Age);

public static void MainTest()
{
 var p1 = new RecordPerson()
 {
  Name = "Tom",
  Age = 12,
 };
 Console.WriteLine(p1);

 var p2 = p1 with { Age = 10 };
 Console.WriteLine(p2);

 var p3 = new RecordPerson() { Name = "Tom", Age = 12 };
 Console.WriteLine(p3);
 Console.WriteLine($"p1 Equals p3 =:{p1 == p3}");

 RecordPerson2 p4 = new("Tom", 12);
 Console.WriteLine(p4);
}

這里的示例,用 record 聲明了兩個(gè) model,第二個(gè) model 聲明的時(shí)候使用了簡化的寫法,

record RecordPerson2(string Name, int Age); 這樣的聲明意味著,構(gòu)造方法有兩個(gè)參數(shù),分別是 string Name int Age,并對(duì)應(yīng)著兩個(gè)屬性,屬性的聲明方式和 RecordPerson 一樣 public string Name { get; init; } 都是一個(gè) get 一個(gè) init

對(duì)于 record 支持一個(gè) with 表達(dá)式,來修改某幾個(gè)屬性的值,這對(duì)于有很多屬性都相同的場(chǎng)景來說是及其方便的,來看一下上面示例的輸出結(jié)果

What inside

那么 record 內(nèi)部發(fā)生了什么呢,我們來反編譯看一下,我們看一下使用 DnSpy 反編譯的結(jié)果

RecordPerson

private class RecordPerson : IEquatable<RecordSample.RecordPerson>
{
 // Token: 0x17000007 RID: 7
 // (get) Token: 0x06000027 RID: 39 RVA: 0x000025F4 File Offset: 0x000007F4
 [Nullable(1)]
 protected virtual Type EqualityContract
 {
  [NullableContext(1)]
  [CompilerGenerated]
  get
  {
   return typeof(RecordSample.RecordPerson);
  }
 }

 // Token: 0x17000008 RID: 8
 // (get) Token: 0x06000028 RID: 40 RVA: 0x00002600 File Offset: 0x00000800
 // (set) Token: 0x06000029 RID: 41 RVA: 0x00002608 File Offset: 0x00000808
 public string Name
 {
  [CompilerGenerated]
  get
  {
   return this.<Name>k__BackingField;
  }
  [CompilerGenerated]
  set
  {
   this.<Name>k__BackingField = value;
  }
 }

 // Token: 0x17000009 RID: 9
 // (get) Token: 0x0600002A RID: 42 RVA: 0x00002611 File Offset: 0x00000811
 // (set) Token: 0x0600002B RID: 43 RVA: 0x00002619 File Offset: 0x00000819
 public int Age
 {
  [CompilerGenerated]
  get
  {
   return this.<Age>k__BackingField;
  }
  [CompilerGenerated]
  set
  {
   this.<Age>k__BackingField = value;
  }
 }

 // Token: 0x0600002C RID: 44 RVA: 0x00002624 File Offset: 0x00000824
 public override string ToString()
 {
  StringBuilder stringBuilder = new StringBuilder();
  stringBuilder.Append("RecordPerson");
  stringBuilder.Append(" { ");
  if (this.PrintMembers(stringBuilder))
  {
   stringBuilder.Append(" ");
  }
  stringBuilder.Append("}");
  return stringBuilder.ToString();
 }

 // Token: 0x0600002D RID: 45 RVA: 0x00002678 File Offset: 0x00000878
 [NullableContext(1)]
 protected virtual bool PrintMembers(StringBuilder builder)
 {
  builder.Append("Name");
  builder.Append(" = ");
  builder.Append(this.Name);
  builder.Append(", ");
  builder.Append("Age");
  builder.Append(" = ");
  builder.Append(this.Age.ToString());
  return true;
 }

 // Token: 0x0600002E RID: 46 RVA: 0x000026EA File Offset: 0x000008EA
 [NullableContext(2)]
 public static bool operator !=(RecordSample.RecordPerson r1, RecordSample.RecordPerson r2)
 {
  return !(r1 == r2);
 }

 // Token: 0x0600002F RID: 47 RVA: 0x000026F6 File Offset: 0x000008F6
 [NullableContext(2)]
 public static bool operator ==(RecordSample.RecordPerson r1, RecordSample.RecordPerson r2)
 {
  return r1 == r2 || (r1 != null && r1.Equals(r2));
 }

 // Token: 0x06000030 RID: 48 RVA: 0x0000270C File Offset: 0x0000090C
 public override int GetHashCode()
 {
  return (EqualityComparer<Type>.Default.GetHashCode(this.EqualityContract) * -1521134295 + EqualityComparer<string>.Default.GetHashCode(this.<Name>k__BackingField)) * -1521134295 + EqualityComparer<int>.Default.GetHashCode(this.<Age>k__BackingField);
 }

 // Token: 0x06000031 RID: 49 RVA: 0x0000274C File Offset: 0x0000094C
 [NullableContext(2)]
 public override bool Equals(object obj)
 {
  return this.Equals(obj as RecordSample.RecordPerson);
 }

 // Token: 0x06000032 RID: 50 RVA: 0x0000275C File Offset: 0x0000095C
 [NullableContext(2)]
 public virtual bool Equals(RecordSample.RecordPerson other)
 {
  return other != null && this.EqualityContract == other.EqualityContract && EqualityComparer<string>.Default.Equals(this.<Name>k__BackingField, other.<Name>k__BackingField) && EqualityComparer<int>.Default.Equals(this.<Age>k__BackingField, other.<Age>k__BackingField);
 }

 // Token: 0x06000033 RID: 51 RVA: 0x000027B0 File Offset: 0x000009B0
 [NullableContext(1)]
 public virtual RecordSample.RecordPerson <Clone>$()
 {
  return new RecordSample.RecordPerson(this);
 }

 // Token: 0x06000034 RID: 52 RVA: 0x000027B8 File Offset: 0x000009B8
 protected RecordPerson([Nullable(1)] RecordSample.RecordPerson original)
 {
  this.Name = original.<Name>k__BackingField;
  this.Age = original.<Age>k__BackingField;
 }

 // Token: 0x06000035 RID: 53 RVA: 0x000027D9 File Offset: 0x000009D9
 public RecordPerson()
 {
 }

 // Token: 0x0400000C RID: 12
 [CompilerGenerated]
 [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 private readonly string <Name>k__BackingField;

 // Token: 0x0400000D RID: 13
 [CompilerGenerated]
 [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 private readonly int <Age>k__BackingField;
}

從上面的反編譯結(jié)果可以看的出來,record 其實(shí)就是一個(gè) class,只是編譯器會(huì)幫我們做一些事情,編譯器幫我們做了哪些事呢?

  • 實(shí)現(xiàn)了基于屬性值的相等性比較,不再使用默認(rèn)的引用,并且重寫了 ==/!= operator 和 GetHashCode
  • 為了方便調(diào)試,重寫了 ToString 方法,也提供了 PrintMembers 方法來實(shí)現(xiàn)比較方便只顯示某些比較重要的參數(shù)
  • 實(shí)現(xiàn)了 EqualityContract 方法來指定類型比較的類型,默認(rèn)是當(dāng)前類型
  • 實(shí)現(xiàn)了 <Clone>$ 方法和一個(gè)特殊的構(gòu)造方法,用來克隆一個(gè)對(duì)象,相當(dāng)于 record 幫我們實(shí)現(xiàn)了一個(gè)淺復(fù)制 的 原型模式,還是強(qiáng)類型的,這個(gè)方法在代碼里不能直接調(diào)用,當(dāng)我們使用 with 表達(dá)式的時(shí)候,編譯器會(huì)調(diào)用這個(gè)方法,并對(duì)某些屬性進(jìn)行賦值

再來看一下 RecordPerson2

private class RecordPerson2 : IEquatable<RecordSample.RecordPerson2>
{
 // Token: 0x06000036 RID: 54 RVA: 0x000027E2 File Offset: 0x000009E2
 public RecordPerson2(string Name, int Age)
 {
  this.Name = Name;
  this.Age = Age;
  base..ctor();
 }

 // Token: 0x1700000A RID: 10
 // (get) Token: 0x06000037 RID: 55 RVA: 0x000027F9 File Offset: 0x000009F9
 [Nullable(1)]
 protected virtual Type EqualityContract
 {
  [NullableContext(1)]
  [CompilerGenerated]
  get
  {
   return typeof(RecordSample.RecordPerson2);
  }
 }

 // Token: 0x1700000B RID: 11
 // (get) Token: 0x06000038 RID: 56 RVA: 0x00002805 File Offset: 0x00000A05
 // (set) Token: 0x06000039 RID: 57 RVA: 0x0000280D File Offset: 0x00000A0D
 public string Name
 {
  [CompilerGenerated]
  get
  {
   return this.<Name>k__BackingField;
  }
  [CompilerGenerated]
  set
  {
   this.<Name>k__BackingField = value;
  }
 }

 // Token: 0x1700000C RID: 12
 // (get) Token: 0x0600003A RID: 58 RVA: 0x00002816 File Offset: 0x00000A16
 // (set) Token: 0x0600003B RID: 59 RVA: 0x0000281E File Offset: 0x00000A1E
 public int Age
 {
  [CompilerGenerated]
  get
  {
   return this.<Age>k__BackingField;
  }
  [CompilerGenerated]
  set
  {
   this.<Age>k__BackingField = value;
  }
 }

 // Token: 0x0600003C RID: 60 RVA: 0x00002828 File Offset: 0x00000A28
 public override string ToString()
 {
  StringBuilder stringBuilder = new StringBuilder();
  stringBuilder.Append("RecordPerson2");
  stringBuilder.Append(" { ");
  if (this.PrintMembers(stringBuilder))
  {
   stringBuilder.Append(" ");
  }
  stringBuilder.Append("}");
  return stringBuilder.ToString();
 }

 // Token: 0x0600003D RID: 61 RVA: 0x0000287C File Offset: 0x00000A7C
 [NullableContext(1)]
 protected virtual bool PrintMembers(StringBuilder builder)
 {
  builder.Append("Name");
  builder.Append(" = ");
  builder.Append(this.Name);
  builder.Append(", ");
  builder.Append("Age");
  builder.Append(" = ");
  builder.Append(this.Age.ToString());
  return true;
 }

 // Token: 0x0600003E RID: 62 RVA: 0x000028EE File Offset: 0x00000AEE
 [NullableContext(2)]
 public static bool operator !=(RecordSample.RecordPerson2 r1, RecordSample.RecordPerson2 r2)
 {
  return !(r1 == r2);
 }

 // Token: 0x0600003F RID: 63 RVA: 0x000028FA File Offset: 0x00000AFA
 [NullableContext(2)]
 public static bool operator ==(RecordSample.RecordPerson2 r1, RecordSample.RecordPerson2 r2)
 {
  return r1 == r2 || (r1 != null && r1.Equals(r2));
 }

 // Token: 0x06000040 RID: 64 RVA: 0x00002910 File Offset: 0x00000B10
 public override int GetHashCode()
 {
  return (EqualityComparer<Type>.Default.GetHashCode(this.EqualityContract) * -1521134295 + EqualityComparer<string>.Default.GetHashCode(this.<Name>k__BackingField)) * -1521134295 + EqualityComparer<int>.Default.GetHashCode(this.<Age>k__BackingField);
 }

 // Token: 0x06000041 RID: 65 RVA: 0x00002950 File Offset: 0x00000B50
 [NullableContext(2)]
 public override bool Equals(object obj)
 {
  return this.Equals(obj as RecordSample.RecordPerson2);
 }

 // Token: 0x06000042 RID: 66 RVA: 0x00002960 File Offset: 0x00000B60
 [NullableContext(2)]
 public virtual bool Equals(RecordSample.RecordPerson2 other)
 {
  return other != null && this.EqualityContract == other.EqualityContract && EqualityComparer<string>.Default.Equals(this.<Name>k__BackingField, other.<Name>k__BackingField) && EqualityComparer<int>.Default.Equals(this.<Age>k__BackingField, other.<Age>k__BackingField);
 }

 // Token: 0x06000043 RID: 67 RVA: 0x000029B4 File Offset: 0x00000BB4
 [NullableContext(1)]
 public virtual RecordSample.RecordPerson2 <Clone>$()
 {
  return new RecordSample.RecordPerson2(this);
 }

 // Token: 0x06000044 RID: 68 RVA: 0x000029BC File Offset: 0x00000BBC
 protected RecordPerson2([Nullable(1)] RecordSample.RecordPerson2 original)
 {
  this.Name = original.<Name>k__BackingField;
  this.Age = original.<Age>k__BackingField;
 }

 // Token: 0x06000045 RID: 69 RVA: 0x000029DD File Offset: 0x00000BDD
 public void Deconstruct(out string Name, out int Age)
 {
  Name = this.Name;
  Age = this.Age;
 }

 // Token: 0x0400000E RID: 14
 [CompilerGenerated]
 [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 private readonly string <Name>k__BackingField;

 // Token: 0x0400000F RID: 15
 [CompilerGenerated]
 [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 private readonly int <Age>k__BackingField;
}

RecordPerson2 相比 RecordPerson 的區(qū)別在于構(gòu)造器不同:

看上面反編譯的結(jié)果,可以看出:

  • RecordPeron2 RecordPerson 都聲明了兩個(gè)屬性,都是 public string Name { get; init; }/public int Age { get; init; }
  • RecordPerson 的構(gòu)造方法是無參構(gòu)造方法,而 RecordPerson2 的構(gòu)造方法是 RecordPerson2(string Name, int Age)
  • 多出來一個(gè) Deconstruct 方法,使得我們可以比較方便的解析一個(gè)對(duì)象的值,可以參考下面這個(gè)示例
foreach (var (name, age) in new[] { p4 })
{
 Console.WriteLine($"{name}={age}");
}

再來看一下測(cè)試方法的反編譯結(jié)果:

RecordSample.RecordPerson p = new RecordSample.RecordPerson
{
 Name = "Tom",
 Age = 12
};
Console.WriteLine(p);
RecordSample.RecordPerson recordPerson = p.<Clone>$();
recordPerson.Age = 10;
RecordSample.RecordPerson p2 = recordPerson;
Console.WriteLine(p2);
RecordSample.RecordPerson p3 = new RecordSample.RecordPerson
{
 Name = "Tom",
 Age = 12
};
Console.WriteLine(p3);
Console.WriteLine(string.Format("p1 Equals p3 =:{0}", p == p3));
RecordSample.RecordPerson2 p4 = new RecordSample.RecordPerson2("Tom", 12);
Console.WriteLine(p4);

這里主要可以看到 with 表達(dá)式的實(shí)現(xiàn),其實(shí)就是調(diào)用 <Clone>$ 方法復(fù)制了一個(gè)對(duì)象,并修改指定的屬性值

More

record 實(shí)現(xiàn)了基于值的相等性比較,并且實(shí)現(xiàn)了 原型模式,可以比較方便的創(chuàng)建一個(gè)新的值完全相等的對(duì)象,這對(duì)于有一些業(yè)務(wù)場(chǎng)景來說是非常適合使用 record 來代替原來的實(shí)現(xiàn)的

Reference

https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9
https://github.com/WeihanLi/SamplesInPractice/tree/master/CSharp9Sample
https://github.com/WeihanLi/SamplesInPractice/blob/master/CSharp9Sample/RecordSample.cs

以上就是C# 9 新特性——record的相關(guān)總結(jié)的詳細(xì)內(nèi)容,更多關(guān)于c# 9 新特性的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C#獲取Windows10屏幕縮放比例的操作方法

    C#獲取Windows10屏幕縮放比例的操作方法

    這篇文章主要介紹了C#獲取Windows10屏幕的縮放比例,接下來介紹如何獲取Display?resolution中顯示的實(shí)際分辨率,本文通過示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2021-12-12
  • 解決在Unity中使用FairyGUI遇到的坑

    解決在Unity中使用FairyGUI遇到的坑

    這篇文章主要介紹了解決在Unity中使用FairyGUI遇到的坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • c#數(shù)學(xué)表示法(后綴表示法)詳解

    c#數(shù)學(xué)表示法(后綴表示法)詳解

    什么是后綴表達(dá)式,查了下原來是一種比較特殊的數(shù)學(xué)表達(dá)式,有三種表達(dá)式:前綴表達(dá)式、中綴表達(dá)式和后綴表達(dá)式,下面我們使用示例學(xué)習(xí)一下
    2014-01-01
  • C# 解壓gizp文件(.tgz)的實(shí)例

    C# 解壓gizp文件(.tgz)的實(shí)例

    下面小編就為大家分享一篇C# 解壓gizp文件(.tgz)的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2017-12-12
  • Unity實(shí)現(xiàn)老虎機(jī)滾動(dòng)抽獎(jiǎng)效果的示例代碼

    Unity實(shí)現(xiàn)老虎機(jī)滾動(dòng)抽獎(jiǎng)效果的示例代碼

    這篇文章主要介紹了Unity實(shí)現(xiàn)老虎機(jī)滾動(dòng)抽獎(jiǎng)效果的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • .net的命名空間類庫的簡單介紹

    .net的命名空間類庫的簡單介紹

    .net的命名空間類庫的簡單介紹,需要的朋友可以參考一下
    2013-04-04
  • 新手小白用C# winform 讀取Excel表的實(shí)現(xiàn)

    新手小白用C# winform 讀取Excel表的實(shí)現(xiàn)

    這篇文章主要介紹了新手小白用C# winform 讀取Excel表的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • C#?SQLite庫使用技巧

    C#?SQLite庫使用技巧

    SQLite是一個(gè)開源、免費(fèi)的小型RDBMS(關(guān)系型數(shù)據(jù)庫),能獨(dú)立運(yùn)行、無服務(wù)器、零配置、支持事物,用C實(shí)現(xiàn),內(nèi)存占用較小,支持絕大數(shù)的SQL92標(biāo)準(zhǔn)。下面跟隨小編一起看下C#?SQLite庫使用
    2022-01-01
  • 老生常談C#?中的?StreamReader?和?StreamWriter?類

    老生常談C#?中的?StreamReader?和?StreamWriter?類

    這篇文章主要介紹了老生常談C#?中的?StreamReader?和?StreamWriter?類,StreamReader?和?StreamWriter?位于?System.IO?命名空間中,當(dāng)您想要讀取或?qū)懭牖谧址臄?shù)據(jù)時(shí),這兩個(gè)類都很有用,需要的朋友可以參考下
    2024-06-06
  • 詳解如何將.NET應(yīng)用轉(zhuǎn)換成Window服務(wù)

    詳解如何將.NET應(yīng)用轉(zhuǎn)換成Window服務(wù)

    這篇文章主要為大家詳細(xì)介紹了如何將.NET8.0應(yīng)用程序轉(zhuǎn)換成Windows服務(wù),文中的示例代碼講解詳細(xì),有需要的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-01-01

最新評(píng)論