<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          還不了解C# 9 新特性?這幾個(gè)特性你應(yīng)該知道!

          共 6434字,需瀏覽 13分鐘

           ·

          2020-11-28 11:18


          轉(zhuǎn)自:東邪獨(dú)孤
          cnblogs.com/tcjiaan/p/13947928.html

          前言


          你一定會(huì)好奇:“老周,你去哪開飛機(jī)了?這么久沒寫博客了。”


          老周:“我買不起飛機(jī),開了個(gè)鐵礦,挖了一年半的石頭。誰知鐵礦垮了,壓死了幾條蜈蚣,什么也沒挖著。”


          所以,這么丟死人的事,還是不要提了,爺爺從小教導(dǎo)我做人要低調(diào)……


          一轉(zhuǎn)眼,.NET 5 要來了,同時(shí)也帶來了 C# 9。遙想當(dāng)年,老周剛接觸 .NET 1.1 的時(shí)候,才剛上大學(xué);如今已經(jīng)過去13年了。歲月是把水果刀,從來不饒人啊。


          老周很少去寫諸如“XXX新特性”之類的文章,總覺得沒啥用處。不過,針對(duì) C# 9,老周想說一點(diǎn)什么。


          好,在開始之前,老周再次強(qiáng)調(diào)一下:這些語言新特性的東西,你千萬不要特意去學(xué)習(xí),千萬不要,不要,不要,重要的事情講四遍!這些玩意兒你只要看看官方給的說明,刷一遍就能掌握了(刷這個(gè)比刷抖音有意義多了),不用去學(xué)的。如果你連這些東東也要學(xué)習(xí)成本的話,我只想說句好唱不好聽的話——你的學(xué)習(xí)能力真的值得懷疑。


          好了,下面開始表演。


          第一出:record 類型


          record ,我還是用原詞吧,我知道有翻譯為“記錄類型”的說法。只是,只是,老周老覺得這不太好聽,可是老周也找不出更好的詞語,還是用回 record吧。


          record 是引用類型,跟 class 很像(確實(shí)差不多)。那么,用人民群眾都熟悉的 class 不香嗎,為何要新增個(gè) record 呢?答:為了數(shù)據(jù)比較的便捷。


          不明白?沒事,往下看。最近有一位熱心鄰居送了老周一只寵物:


          public class Cat
          {
          public string Nick { get; set; }
          public string Name { get; set; }
          public int Age { get; set; }
          }


          這只新寵物可不簡(jiǎn)單,一頂一的高級(jí)吃貨。魚肉、豬肉、雞腿、餅干、豆腐、面包、水果、面條、小麥、飛蛾……反正,只要它能塞進(jìn)嘴里的,它都吃。


          接下來,我們 new 兩個(gè)寵物實(shí)例。


          // 兩個(gè)實(shí)例描述的是同一只貓
          Cat pet1 = new Cat
          {
          Nick = "松子",
          Name = "Jack",
          Age = 1
          };
          Cat pet2 = new Cat
          {
          Nick = "松子",
          Name = "Jack",
          Age = 1
          };
          // 居然不是同一只貓
          Console.WriteLine("同一只?{0}", pet1 == pet2);


          其實(shí),兩個(gè)實(shí)例描述的都是我家的乖乖。可是,輸出的是:


          同一只?False


          這是因?yàn)椋谙嗟缺容^時(shí),人家關(guān)心的類型引用——引用的是否為同一個(gè)實(shí)例。但是,在數(shù)據(jù)處理方案中,我們更關(guān)注對(duì)象中的字段/屬性是否相等,即內(nèi)容比較。


          現(xiàn)在,把 Cat 的聲明改為 record 類型。


          public record Cat
          {
          public string Nick { get; set; }
          public string Name { get; set; }
          public int Age { get; set; }
          }


          然后同樣用上面的 pet1 和 pet2 實(shí)例進(jìn)行相等比較,得到預(yù)期的結(jié)果:


          同一只?True


          record 類型讓你省去了重寫相等比較(重寫 Equals、GetHashCode 等方法或重載運(yùn)算符)的邏輯。


          實(shí)際上,代碼在編譯后 record 類型也是一個(gè)類,但自動(dòng)實(shí)現(xiàn)了成員相等比較的邏輯。以前你要手動(dòng)去折騰的事現(xiàn)在全交給編譯器去干。


          假如,有一個(gè) User 類型,用于表示用戶信息(包括用戶名、密碼),然后這個(gè) User 類型在數(shù)據(jù)處理方案中可能會(huì)產(chǎn)生N多個(gè)實(shí)例。例如你根據(jù)條件從EF模型中篩選出一個(gè) User 實(shí)例 A,根據(jù)用戶輸入的登錄名和密碼產(chǎn)生了 User 實(shí)例 B。為了驗(yàn)證用戶輸入的登錄信息是否正確,如果 User 是 class,你可能要這樣判斷:


          if(A.UserName == B.UserName && A.Password == B.Password)
          {
          ..................
          }


          但要是你把 User 定義為 record 類型,那么,一句話的工夫:


          A == B


          第二出:模式匹配(Pattern Matching)


          "模式匹配"這個(gè)翻譯感覺怪怪滴,老周還沒想出什么更好的詞語。模式匹配并不是什么神奇的東西,它只是在對(duì)變量值進(jìn)行檢測(cè)時(shí)的擴(kuò)展行為。以前,老感覺C++/C# 的 switch 語句不夠強(qiáng)大,因?yàn)閭鹘y(tǒng)的用法里面,每個(gè) case 子句只能比較單個(gè)常量值。比如


          int 考試成績(jī) = 85;
          switch (考試成績(jī))
          {
          case 10:
          Console.WriteLine("才考這么點(diǎn)破分啊");
          break;
          case 50:
          Console.WriteLine("還差一點(diǎn),就合格了");
          break;
          case 85:
          Console.WriteLine("真是秀");
          break;
          case 90:
          Console.WriteLine("奇跡發(fā)生");
          break;
          }


          我幻想著,要是能像下面這樣寫就好了:


          switch (考試成績(jī))
          {
          case 0:
          Console.WriteLine("缺考?");
          break;
          case > 0 && <= 30:
          Console.WriteLine("太爛了");
          break;
          case > 30 && < 60:
          Console.WriteLine("還是不行");
          break;
          case >= 60 && < 80:
          Console.WriteLine("還得努力");
          break;
          case >= 80 && < 90:
          Console.WriteLine("秀兒,真優(yōu)秀");
          break;
          case >= 90 && <= 100:
          Console.WriteLine("不錯(cuò),奇跡");
          break;
          }


          等了很多年很多年(“千年等一回,等……”)以后,終于可以實(shí)現(xiàn)了。


          switch (考試成績(jī))
          {
          case 0:
          Console.WriteLine("缺考?");
          break;
          case > 0 and <= 30:
          Console.WriteLine("太爛了");
          break;
          case > 30 and < 60:
          Console.WriteLine("還是不行");
          break;
          case >= 60 and < 80:
          Console.WriteLine("還得努力");
          break;
          case >= 80 and < 90:
          Console.WriteLine("秀兒,真優(yōu)秀");
          break;
          case >= 90 and <= 100:
          Console.WriteLine("不錯(cuò),奇跡");
          break;
          }


          喲西,真香。


          有時(shí)候,不僅要檢測(cè)對(duì)象的值,還得深入到其成員。比如下面這個(gè)例子,Order類表示一條訂單信息。


          public class Order
          {
          public int ID { get; set; }
          public string Company { get; set; }
          public string ContactName { get; set; }
          public float Qty { get; set; }
          public decimal UP { get; set; }
          public DateTime Date { get; set; }
          }


          前不久,公司接到一筆Order,做成了收益應(yīng)該不錯(cuò)。


          Order od = new Order
          {
          ID = 11,
          Company = "大嘴狗貿(mào)易有限公司",
          ContactName = "陳大爺",
          Qty = 425.12f,
          UP = 1000.55M,
          Date = new(2020, 10, 27)
          };


          假如我要在變量 od 上做 switch,看看,就這樣:


          switch (od)
          {
          case { Qty: > 1000f }:
          Console.WriteLine("發(fā)財(cái)了,發(fā)財(cái)了");
          break;
          case { Qty: > 500f }:
          Console.WriteLine("好家伙,年度大訂單");
          break;
          case { Qty: > 100f }:
          Console.WriteLine("訂單量不錯(cuò)");
          break;
          }


          咦?這,這是什么鬼?莫驚莫驚,這不是鬼。它的意思是判斷 Qty 屬性的值,如果訂單貨量大于 100 就輸出“訂單量不錯(cuò)”;要是訂單貨量大于 1000,那就輸出“發(fā)財(cái)了,發(fā)財(cái)了”。


          但你會(huì)說,這對(duì)大括號(hào)怎么來的呢?還記得這種 LINQ 的寫法嗎?


          from x in ...
          where x.A ...
          select new {
          Prop1 = ...,
          Prop2 = ...,
          ................
          }


          new { ... } 是匿名類型實(shí)例,那如果是非匿名類型呢,看看前面的 Cat 實(shí)例初始化。


          Cat {
          ..........
          }


          這就對(duì)了,這對(duì)大括號(hào)就是構(gòu)造某實(shí)例的成員值用的,所以,上面的 switch 語句其實(shí)是這樣寫的:


          switch (od)
          {
          case Order{ Qty: > 1000f }:
          Console.WriteLine("發(fā)財(cái)了,發(fā)財(cái)了");
          break;
          case Order{ Qty: > 500f }:
          Console.WriteLine("好家伙,年度大訂單");
          break;
          case Order{ Qty: > 100f }:
          Console.WriteLine("訂單量不錯(cuò)");
          break;
          }


          Order{ ... } 就是匹配一個(gè) Order 對(duì)象實(shí)例,并且它的 Qty 屬性要符合 ... 條件。由于變量 od 始終就是 Order 類型,所以,case 子句中的 Order 就省略了,變成


          case { Qty: > 1000f }:
          Console.WriteLine("發(fā)財(cái)了,發(fā)財(cái)了");
          break;


          如果出現(xiàn)多個(gè)屬性,則表示為多個(gè)屬性設(shè)定匹配條件,它們之間是“且”的關(guān)系。比如


          case { Qty: > 100f, Company: not null }:
          Console.WriteLine("訂單量不錯(cuò)");
          break;


          猜猜啥意思?這個(gè)是可以“望文生義”的,Qty 屬性的值要大于 100,并且 Company 屬性的值不能為 null。不為 null 的寫法是 not null,不要寫成 !null,因?yàn)檫@樣太難看了。


          如果你的代碼分支較少,你可以用 if 語句的,只是得配合 is 運(yùn)算符。


          if (od is { UP: < 3000M })
          {
          Console.WriteLine("報(bào)價(jià)不理想");
          }


          但是,這個(gè)寫法目前有局限性,它只能用常量值來做判斷,你要是這樣寫就會(huì)報(bào)錯(cuò)。


          if (od is { Date: < DateTime.Now })
          {
          ...............
          }


          DateTime.Now 不是常量值,上面代碼無法通過編譯。


          is 運(yùn)算符以前是用來匹配類型的,上述的用法是它的語法擴(kuò)展。


          object n = 5000000L;
          if(n is long)
          {
          Console.WriteLine("它是個(gè)長(zhǎng)整型");
          }


          進(jìn)化之后的 is 運(yùn)算符也可以這樣用:


          object n = 5000000L;
          if(n is long x)
          {
          Console.WriteLine("它是個(gè)長(zhǎng)整型,存放的值是:{0}", x);
          }


          如果你在 if 語句內(nèi)要使用 n 的值,就可以順便轉(zhuǎn)為 long 類型并賦值給變量 x,這樣就一步到位,不必再去寫一句 long x = (long)n 。


          如果 switch... 語句在判斷之后需要返回一個(gè)值,還可以把它變成表達(dá)式來用。咱們把前面的 Order 例子改一下。


          string message = od switch
          {
          { Qty: > 1000f } => "發(fā)財(cái)了",
          { Qty: > 500f } => "年度大訂單",
          { Qty: > 100f } => "訂單量不錯(cuò)",
          _ => "未知"
          };
          Console.WriteLine(message);


          這時(shí)候你得注意:


          1、switch 現(xiàn)在是表達(dá)式,不是語句塊,所以最后大括號(hào)右邊的分號(hào)不能少;


          2、因?yàn)?switch 成了表達(dá)式,就不能用 case 子句了,所以直接用具體的內(nèi)容來匹配;


          3、最后返回“未知”的那個(gè)下劃線(_),也就是所謂的“棄嬰”,哦不,是“棄元”,就是雖然賦了值但不需要使用的變量,可以直接丟掉。這里就相當(dāng)于 switch 語句塊中的 default 子句,當(dāng)前面所有條件都不能匹配時(shí),就返回“未知”。


          第三出:屬性的 init 訪問器


          要首先得知道,這個(gè) init 只用于只讀屬性的初始化階段,對(duì)于可讀可寫的屬性,和以前一樣,直接 get; set; 即可。


          有人說這個(gè) init 不知干啥用,那好,咱們先不說它,先來看看 C# 前些版本中新增的屬性初始化語句。


          public class Dog
          {
          public int No { get; } = 0;
          public string Name { get; } = "no name";
          public int Age { get; } = 1;
          }


          你看,這樣就可以給屬性分配初始值了,那還要 init 干嗎呢?


          好,我給你制造一個(gè)問題——我要是這樣初始化 Dog 類的屬性,你試試看。


          Dog x = new Dog
          {
          No = 100,
          Name = "吉吉",
          Age = 4
          };


          試一下,編譯會(huì)出錯(cuò)吧。



          有些情況,你可以在屬性定義階段分配初始值,但有些時(shí)候,你必須要在代碼中初始化。在過去,我們會(huì)通過定義帶參數(shù)的構(gòu)造函數(shù)來解決。


          public class Dog
          {
          public int No { get; } = 0;
          public string Name { get; } = "no name";
          public int Age { get; } = 1;
          public Dog(int no, string name, int age)
          {
          No = no;
          Name = name;
          Age = age;
          }
          }


          然后,這樣初始化。


          Dog x = new(1001, "吉吉", 4);


          可是,這樣做的裝逼指數(shù)依然不夠高,你總不能每個(gè)類都來這一招吧,雖然不怎么辛苦,但每個(gè)類都得去寫一個(gè)構(gòu)造函數(shù),不利落。


          于是,init 訪問器用得上了,咱們把 Dog 類改改。


          public class Dog
          {
          public int No { get; init; }
          public string Name { get; init; }
          public int Age { get; init; }
          }


          你不用再去寫帶參數(shù)的構(gòu)造函數(shù)了,實(shí)例化時(shí)直接為屬性賦值。


          Dog x = new Dog
          {
          No = 100,
          Name = "吉吉",
          Age = 4
          };


          這樣一來,這些只讀屬性都有默認(rèn)的初始值了。


          當(dāng)然,這個(gè)賦值只在初始化過程中有效,初始化之后你再想改屬性的值,沒門!


          x.Name = "冬冬";  //錯(cuò)誤
          x.Age = 10; //錯(cuò)誤


          嗯,好了,以上就是老周對(duì) C# 9 新特性用法的一些不成文的闡述。看完后你就別說難了。


          - EOF -



          如果你也有好的開源項(xiàng)目,歡迎推薦!

          微信號(hào)聯(lián)系:westbrook12000(ps:加好友請(qǐng)備注“開源”)

          回復(fù)?【小程序】獲取15套小程序源碼【學(xué)習(xí)+實(shí)戰(zhàn)+賺錢】
          回復(fù)?【關(guān)閉】學(xué)關(guān)閉微信朋友圈廣告
          回復(fù)?【實(shí)戰(zhàn)】獲取20套實(shí)戰(zhàn)源碼
          回復(fù)?【福利】獲取最新微信支付有獎(jiǎng)勵(lì)
          回復(fù)?【被刪】學(xué)查看你哪個(gè)好友刪除了你巧
          回復(fù)?【訪客】學(xué)微信查看朋友圈訪客記錄
          回復(fù)?【python】學(xué)微獲取全套0基礎(chǔ)Python知識(shí)手冊(cè)

          臥槽,又來一堆VSCode 摸魚神器!


          別到處借會(huì)員了,這里啥都有!高清全免費(fèi)!



          瀏覽 68
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  青青草天天免费在线 | 黄色美女大奶被操日韩 | 99热在线观看免费 | 青娱乐户外黄色片 | 自拍偷拍51页 |