最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#9.0:Init相關(guān)總結(jié)

 更新時(shí)間:2021年02月02日 08:58:22   作者:翁智華  
這篇文章主要介紹了C#9.0:Init的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)新版的c#,感興趣的朋友可以了解下

背景

在以前的C#版本里面,如果需要定義一個(gè)不可修改的的類型的做法一般是:聲明為readonly,并設(shè)置為只包含get訪問器,不包含set訪問器。如下:

public class PersonInfo
 {
  /// <summary>
  /// 身份編號(hào)
  /// </summary>
  public string UserCode { get; }

  /// <summary>
  /// 姓名
  /// </summary>
  public string UserName { get; }

  /// <summary>
  /// 初始化賦值
  /// </summary>
  /// <param name="_userCode"></param>
  /// <param name="_userName"></param>
  public PersonInfo(string _userCode,string _userName)
  {
   UserCode = _userCode;
   UserName = _userName;
  }
 }

這種方式是可行的,也達(dá)到我們的目的,但是代碼量多,需要增加額外的構(gòu)造方法來實(shí)現(xiàn)初始化賦值,并且如果字段越多,帶參構(gòu)造函數(shù)也會(huì)越大,開發(fā)工作量也越大,更不好維護(hù)。

為了改變這種狀態(tài),C#9.0提供了一種解決方案:在對(duì)象初始換的時(shí)候就配置為只讀的方式。

特別對(duì)一口氣創(chuàng)建含有嵌套結(jié)構(gòu)的樹狀對(duì)象來說更有用。下面是一個(gè)用戶信息初始化的案例:

PersonInfo pi = new PersonInfo() { UserCode="1234567890", UserName="Brand" }; 

從這個(gè)例子說明了,要進(jìn)行對(duì)象初始化,我們必須先要在需要初始化的屬性中添加set訪問器,然后才能在對(duì)象初始化器中通過給屬性或者索引器賦值來實(shí)現(xiàn)。如下:

public class PersonInfo
 {
  /// <summary>
  /// 身份編號(hào)
  /// </summary>
  public string UserCode { get; set; }

  /// <summary>
  /// 姓名
  /// </summary>
  public string UserName { get; set; }
 }

所以對(duì)于初始化來說,屬性必須是可變的,set訪問器就必須存在。這就是問題所在,很多情況下為了避免屬性初始化之后再被改變,就需要不可變對(duì)象類型,因此setter訪問器在這里明顯不適用。

基于這種有這種常見的需要和局限性,C#9.0引入了只用來初始化的init設(shè)置訪問器。這時(shí),上面的PersonInfo類就可以定義成下面的樣子:

public class PersonInfo
 {
  /// <summary>
  /// 身份編號(hào)
  /// </summary>
  public string? UserCode { get; init; }

  /// <summary>
  /// 姓名
  /// </summary>
  public string? UserName { get; init; }
 }

這邊通過采用init訪問器,代碼變得簡(jiǎn)潔易懂了,滿足了上面的只讀需求,而且更易編碼和維護(hù)。

定義和使用

init(只初始化屬性或索引器訪問器):只在對(duì)象構(gòu)造階段進(jìn)行初始化時(shí)可以用來賦值,算是set訪問器的變體,set訪問器的位置使用init來替換。init有著如下限制:

1、init訪問器只能用在實(shí)例屬性或索引器中,靜態(tài)屬性或索引器中不可用。

2、屬性或索引器不能同時(shí)包含init和set兩個(gè)訪問器

3、如果基類的屬性有init,那么屬性或索引器的所有相關(guān)重寫,都必須有init。接口也一樣。

什么時(shí)候設(shè)置init訪問器

除過在局部方法和lambda表達(dá)式中,帶有init訪問器的屬性和索引器可以在下面幾種情況中可設(shè)置的。這幾個(gè)設(shè)置的時(shí)機(jī)都是在對(duì)象的構(gòu)造階段。過了構(gòu)造階段,后續(xù)賦值操作就不允許了。

1、在對(duì)象初始化器工作期間

2、在with表達(dá)式初始化器工作期間

3、在所處或者派生的類型的實(shí)例構(gòu)造函數(shù)中,在this或者base使用上

4、在任意屬性init訪問器里面,在this或者base使用上

5、在帶有命名參數(shù)的attribute使用中

在這些限制條件下,意味著我們上面定義的PersonInfo只能在對(duì)象初始化的時(shí)候使用,第二次賦值就不被允許了。

即:一旦初始化完成之后,只初始化屬性或索引就保護(hù)著對(duì)象的狀態(tài)免于改變。

 var person = new PersonInfo() { UserCode="12345678", UserName="Brand" };
 //提示錯(cuò)誤:只能在對(duì)象初始器或?qū)嵗龢?gòu)造函數(shù)中分配 init-only
 person.UserName = "Brand1"; 

init屬性訪問器和只讀字段

因?yàn)閕nit訪問器只能在初始化時(shí)被調(diào)用,所以在init屬性訪問器中可以改變封閉類的只讀字段。

需要注意的是,從init訪問器中來給readonly字段賦值僅限于跟init訪問器處于同一類型中定義的字段,通過它是不能給父類中定義的readonly字段賦值的,關(guān)于這繼承有關(guān)的示例,我們會(huì)在2.4類型間的層級(jí)傳遞中看到。

public class PersonInfo
 {
  private readonly string userCode = "<unknown>";
  private readonly string userName = "<unknown>";

  public string UserCode
  {
   get => userCode;
   init => userCode = (value ?? throw new ArgumentNullException(nameof(UserCode)));
  }
  public string UserName
  {
   get => userName;
   init => userName = (value ?? throw new ArgumentNullException(nameof(UserName)));
  }
 }

類型層級(jí)間的傳遞

我們知道只包含get訪問器的屬性或索引器只能在所處類的自身構(gòu)造函數(shù)中被初始化,但init訪問器可以進(jìn)行設(shè)置的規(guī)則是可以跨類型層級(jí)傳遞的。

帶有init訪問器的成員只要是可訪問的,對(duì)象實(shí)例并能在構(gòu)造階段被知曉,那這個(gè)成員就是可設(shè)置的。

1、在對(duì)象初始化中使用,是允許的

public class PersonInfo
 {
  /// <summary>
  /// 身份編號(hào)
  /// </summary>
  public string UserCode { get; init; }

  /// <summary>
  /// 姓名
  /// </summary>
  public string UserName { get; init; }

  public PersonInfo()
  {
   UserCode = "1234567890";
   UserName = "Brand";
  }
 }

2、在派生類的實(shí)例構(gòu)造函數(shù)中,也是允許的,如下面這兩個(gè)例子:

public class PersonInfoExt : PersonInfo
 {
  public PersonInfoExt()
  {
   UserCode = "1234567890_0";
   UserName = "Brand1";
  }
 }
var personext = new PersonInfoExt() { UserCode="1234567890_2", UserName="Brand2" };

從init訪問器能被調(diào)用這一方面來看,對(duì)象實(shí)例在開放的構(gòu)造階段就可以被知曉。因此除過正常set可以做之外,init訪問器的下列行為也是被允許的。

1、通過this或者base調(diào)用其他可用的init訪問器

2、在同一類型中定義的readonly字段,是可以通過this給賦值的

init中是不能更改父類中的readonly字段的,只能更改本類中readonly字段。示例代碼如下:

class PersonInfo1
 {
  protected readonly string UserCode_R;
  public String UserCode
  {
   get => UserCode_R;
   init => UserCode_R = value; // 正確:在同一類中定義的readonly屬性,可以直接通過this給賦值的
  }
  internal String UserName { get; init; }
 }

 class PersonInfo1Ext : PersonInfo1
 {
  protected readonly int NewField;
  internal int NewProp
  {
   get => NewField;
   init
   {
    NewField = 100; // 正確
    UserCode = "123456";  // 正確
    UserCode_R = "1234567";  // 出錯(cuò),試圖修改基類中的readonly字段UserCode_R
   }
  }

  public PersonInfo1Ext()
  {
   UserCode = "123456"; // 正確
   UserCode_R = "1234567"; // 出錯(cuò),試圖修改基類中的readonly字段UserCode_R
  }
 }

如果init被用于virtual修飾的屬性或者索引器,那么所有的覆蓋重寫都必須被標(biāo)記為init,是不能用set的。同樣地,我們不可能用init來覆蓋重寫一個(gè)set的。

public class PersonInfo
 {
  /// <summary>
  /// 身份編號(hào)
  /// </summary>
  public virtual string UserCode { get; init; }

  /// <summary>
  /// 姓名
  /// </summary>
  public virtual string UserName { get; set; }
 }

 public class PersonInfoExt1 : PersonInfo
 {
  public override string UserCode { get; init; }
  public override string UserName { get; set; }
 }

 public class PersonInfoExt2 : PersonInfo
 {
  // 錯(cuò)誤: 基類的init屬性必須由init來重寫PersonInfo.UserCode
  public override int UserCode { get; set; }
  // 錯(cuò)誤: 基類的init屬性必須由set來重寫PersonInfo.UserName
  public override string UserName { get; init; }
 }

init在接口接口中應(yīng)用

一個(gè)接口中的默認(rèn)實(shí)現(xiàn),也是可以采用init進(jìn)行初始化,下面就是一個(gè)應(yīng)用模式示例。

interface IPersonInfo
 {
  string Usercode { get; init; }
  string UserName { get; init; }
 }

 class PersonInfo
 {
  void NewPersonInfo<T>() where T : IPersonInfo, new()
  {
   var person = new T()
   {
    Usercode = "1234567890",
    UserName = "Jerry"
   };
   person.Usercode = "111"; // 錯(cuò)誤
  }
 }

init訪問器是允許在readonly struct中的屬性中使用的,init和readonly的目標(biāo)都是一致的,就是只讀。示例代碼如下:

readonly struct PersonInfo
 {
  /// <summary>
  /// 身份編號(hào)
  /// </summary>
  public string UserCode { get; init; }

  /// <summary>
  /// 姓名
  /// </summary>
  public string UserName { get; set; }
 }

但是要注意的是:

1、不管是readonly結(jié)構(gòu)還是非readonly結(jié)構(gòu),不管是手工定義屬性還是自動(dòng)生成屬性,init都是可以使用的。

2、init訪問器本身是不能標(biāo)記為readonly的。但是所在屬性或索引器可以被標(biāo)記為readonly

struct PersonInfo
 {
  /// <summary>
  /// 身份編號(hào)
  /// </summary>
  public readonly string UserCode { get; init; }

  /// <summary>
  /// 姓名
  /// </summary>
  public string UserName { get; readonly init; }
 }

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

相關(guān)文章

  • C#中LINQ多條件JOIN時(shí)為什么可以使用匿名類

    C#中LINQ多條件JOIN時(shí)為什么可以使用匿名類

    這篇文章主要給大家介紹了關(guān)于C#中LINQ多條件JOIN時(shí)為什么可以使用匿名類的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來一起看看吧
    2018-09-09
  • 基于C#實(shí)現(xiàn)進(jìn)程回收管理工具

    基于C#實(shí)現(xiàn)進(jìn)程回收管理工具

    這篇文章主要為大家詳細(xì)介紹了入戶基于C#實(shí)現(xiàn)一個(gè)進(jìn)程回收管理工具,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-04-04
  • C#對(duì)文件名智能排序的算法

    C#對(duì)文件名智能排序的算法

    這篇文章介紹了C#對(duì)文件名智能排序的算法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • c#給圖片添加文字的代碼小結(jié)

    c#給圖片添加文字的代碼小結(jié)

    c#編程中,我們需要為圖片添加文字水印,那么就可以參考下面的幾個(gè)代碼
    2012-11-11
  • Unity3D運(yùn)行報(bào)DllNotFoundException錯(cuò)誤的解決方案

    Unity3D運(yùn)行報(bào)DllNotFoundException錯(cuò)誤的解決方案

    這篇文章主要介紹了Unity3D運(yùn)行報(bào)DllNotFoundException錯(cuò)誤的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • Unity3d 如何更改Button的背景色

    Unity3d 如何更改Button的背景色

    這篇文章主要介紹了unity3d GUI.Button 自定義字體大小及透明背景方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • c#如何利用定時(shí)器自動(dòng)備份數(shù)據(jù)庫詳解

    c#如何利用定時(shí)器自動(dòng)備份數(shù)據(jù)庫詳解

    在開發(fā)過程當(dāng)中,你一定遇到文件損壞活或丟失的煩惱,而每天備份又很麻煩,你只要設(shè)置每天備份的時(shí)間,并將程序加入啟動(dòng)項(xiàng)中,就可以自動(dòng)完成備份,這篇文章主要給大家介紹了關(guān)于c#如何利用定時(shí)器自動(dòng)備份數(shù)據(jù)庫的相關(guān)資料,需要的朋友可以參考下
    2021-10-10
  • LINQ操作符SelectMany的用法

    LINQ操作符SelectMany的用法

    這篇文章介紹了LINQ操作符SelectMany的用法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-02-02
  • C#使用itextsharp打印pdf的實(shí)現(xiàn)代碼

    C#使用itextsharp打印pdf的實(shí)現(xiàn)代碼

    提到打印,恐怕對(duì)于很多人都不會(huì)陌生,無論是開發(fā)者,還是非計(jì)算機(jī)專業(yè)的人員都會(huì)接觸到打印,?在.NET中實(shí)現(xiàn)PDF打印的組件比較多,例如PDFsharp、Report.NET、sharpPDF、itextSharp等等,今天主要簡(jiǎn)單的介紹itextSharp組件,需要的朋友可以參考下
    2024-04-04
  • C#實(shí)現(xiàn)日期格式轉(zhuǎn)換的公共方法類實(shí)例

    C#實(shí)現(xiàn)日期格式轉(zhuǎn)換的公共方法類實(shí)例

    這篇文章主要介紹了C#實(shí)現(xiàn)日期格式轉(zhuǎn)換的公共方法類,結(jié)合完整實(shí)例形式分析了C#針對(duì)各種常見日期格式的轉(zhuǎn)換方法,涉及C#字符串、日期、時(shí)間相關(guān)操作技巧,需要的朋友可以參考下
    2017-01-01

最新評(píng)論

霍邱县| 应用必备| 鞍山市| 韶关市| 合山市| 和平区| 刚察县| 济源市| 三河市| 红河县| 电白县| 咸丰县| 桐柏县| 兴安盟| 新营市| 宾川县| 神农架林区| 会理县| 诸城市| 深水埗区| 嘉义市| 于都县| 玛沁县| 绥棱县| 忻城县| 和田县| 辰溪县| 通州区| 横峰县| 璧山县| 汉阴县| 北宁市| 太湖县| 开平市| 太白县| 高雄县| 山东| 阳泉市| 兴国县| 舞阳县| 资兴市|