再来说说我喜欢的 Dotnet 5.0 C# 9
上次寫完 C# 10,有兄弟在后臺問 C# 9,就再開個篇寫一寫。
C# 9,對應的是 Dotnet 5.0。
這個出來也有些日子了,不過好像群里很多人還是沒往這個版本走。
我這邊現(xiàn)在是全線已經(jīng)轉(zhuǎn)向了 5.0,還是我經(jīng)常說的那個原因:爽。Dotnet 的每一次升級,都有一些讓人驚喜的特性,讓代碼更合理,更節(jié)省時間。
1. 基礎語言方面
語言方面,最主要的特性,是 Record。這是 C# 9 出來的一個新數(shù)據(jù)類型。沒錯,Record 是一個數(shù)據(jù)類型。
這個 Record 提供了一些很爽的表示數(shù)據(jù)的內(nèi)置功能,以至于使用的時候,感覺它更像一個類。
按微軟的說法,Record 的目的,是提供一個更小更簡單的類型來表示不可變數(shù)據(jù)。不過在使用中,我更喜歡用它來做數(shù)據(jù)傳輸。
定義一個 Record
定義一個 Record 有幾種方式。最簡單的形式是:
public?record?User(?string?name,?int?age?);第一次看這個東西,會有點奇怪,有沒有?長得有點像方法,可就沒內(nèi)容。
嗯,這確實是 Record 的一個聲明定義,定義了一個對象 user,這個對象 user 具有 name 和 age 兩個屬性。可以通過以下方式來訪問:
var?some_user?=?new?User?(?"WangPlus",?35?); Console.WriteLine(?some_user.name?);????//輸出?WangPlus Console.WriteLine(?some_user.age?);????????//輸出?35確實跟類有點像。
再來看看另一種定義方式,會更像一個類:
public?record?User {public?string?name?{?get;?set;?}public?int?age?{?get;?set;?} }給 Record 賦值
既然長得像類,我們可以像類一樣去賦值:
var?some_user?=?new?User?{?name?=?"WangPlus",?age?=?35?};還可以用位置語法,近一步簡化:
User?some_user?=?new?(?"WangPlus",?35?);注意這個位置語法,其實就是按位置匹配字段的意思。賦值時的值,會自動去找對應位置的屬性來匹配和校驗。
而且,對于第一種簡單定義:
public?record?User(?string?name,?int?age?);賦值語句實際編譯時,上面字段中的 set 會被替換為 init,即:
public?record?User {public?string?name?{?get;?init;?}public?int?age?{?get;?init;?} }這意味著屬性在初始化后無法改變,會變成只讀屬性。
相等判斷
Record 對于相等的定義是內(nèi)部的屬性相等。也就是說,判斷兩個 Record 是否相等時,將檢查每個屬性的值,而不是對象的引用地址。
看例子:
User?some_user1?=?new?("WangPlus",?35); User?some_user2?=?new?("WangPlus",?35); Console.WriteLine(some_user1?==?some_user2);????//?true Console.WriteLine(ReferenceEquals(some_user1,?some_user2));????//?false例子中,some_user1 和 some_user2 屬性相同,所以他們是相等的,盡管是兩個不同的引用。
不一樣的 ToString()
Record 的 ToString 是一個內(nèi)置方法,跟別的對象的 ToString 有很大區(qū)別。它會把 Record 的定義、屬性和值全部輸出。上面的例子,輸出的內(nèi)容將會是:
User?{?name?=?WangPlus,?age?=?35?}注意:如果某個 Record 的屬性是引用類型,ToString 將會輸出這個類型的名稱。
Record 值的傳遞
這個內(nèi)容延續(xù)到了 C# 10,相關內(nèi)容我在 「Dotnet 6.0,你值得擁有」里有詳細的描述,可以去看看。
這里簡單說一下,就是使用 With:
User?some_user?=?new?(?"WangPlus",?35?); User?other_user?=?some_user?with?{?name?=?"WangPlus1"?};定義 Init 屬性
C# 9 里,新增了一個對于屬性定義的 init 關鍵字。這個關鍵字可以用在 Struct、Class、Record 中,表示屬性僅在初始化時可以進行設置。
例如:
public?record?User {public?string?name?{?get;?set;?}public?int?age?{?get;?init;?} }這里,age 屬性被定義為 init。賦值還是一樣的:
User?some_user?=?new?(?"WangPlus",?35?);當改變值時,例如:
some_user.name?=?"WangPlus1";這個是有效的,但是:
some_user.age?=?36;這句話會報錯,因為在上面定義中,age 被定義為 init,即只有初始化時可以賦值。
以上是 C# 9 中增加的最重要的一個內(nèi)容:Record 類型。
2. API 方面
API 方面,主要是三個特性。
1. 頂級程序
這算是大家盼了很久的一個特性。
早期,一個程序的開始,會是這個樣子:
using?System;namespace?Demo {static?class?Program{static?void?Main(string[]?args){Console.WriteLine("Hello?World!");}} }現(xiàn)在有了頂級程序的規(guī)則,這一大段,可以直接簡化為:
System.Console.WriteLine("Hello?World");就OK了。Program 啦,Main 啦,統(tǒng)統(tǒng)都可以不寫了。
對于 WebAPI 應用也一樣:
using?Microsoft.AspNetCore.Hosting; using?Microsoft.Extensions.Hosting;namespace?Demo {public?class?Program{public?static?void?Main(string[]?args){CreateHostBuilder(args).Build().Run();}public?static?IHostBuilder?CreateHostBuilder(string[]?args)?=>Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder?=>{webBuilder.UseStartup<Startup>();});} }這是一個標準的 WebAPI 應用的開始。現(xiàn)在,也可以簡化成:
using?Microsoft.AspNetCore.Hosting; using?Microsoft.Extensions.Hosting;CreateHostBuilder(args).Build().Run();IHostBuilder?CreateHostBuilder(string[]?args)?=>Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder?=>{webBuilder.UseStartup<Startup>();});這樣的代碼其實更簡潔,而且可以直觀的說明程序的意圖。如果你也經(jīng)常寫 Python,那你會很喜歡這個特性。
2. 新的匹配模式
C# 9 里,終于加入了大家期盼已久的新的匹配模式。主要有兩類:
第一類:邏輯匹配
這個主要是加入了 And、Or 和 Not。
以前,我們會用到這樣的判斷:
if(?input?==?null?)?{}有時候,我們也會寫成:
if(?input?is?null?)?{}但是,判斷不等于時,我們只有一種方式,就是:
if(?input?!=?null?)?{}現(xiàn)在,我們有了更可讀的寫法:
if(?int?is?not?null?)?{}看起來可讀性就很高了。
第二類:關系匹配
這個特性,涉及的是 <、>、<=、>=,最主要的是改變了 Switch。
以前,使用 Switch 時,Case 必須是可枚舉的值,看例子:
switch(?input?) {case?1:break;case?2:break;default:break; }現(xiàn)在,這里面加入了范圍判斷,可以這么寫:
switch(?input?) {case?<5:break;case?>=5?and?<=9:break;default:break; }看到?jīng)]?更多的邏輯可以在 Switch 里實現(xiàn),而不用一大篇 if…else 了。
3. 類型省略
這個特性涉及到代碼的方方面面,主要的目的,是為了減少代碼的輸入量。
看個例子,以前我們定義一個字段,通常是這樣:
public?List<User>?users?=?new?List<User>();現(xiàn)在,我們可以直接省略后面的部分,編譯器會很聰明的知道我們想 New 什么:
public?List<User>?users?=?new?();方法也是一樣。假設我們有一個方法:
public?static?class?Users {public?User?copyUser(User?source)?{} }以前調(diào)用時,我們需要先給個變量,再調(diào)用方法:
User?source_user?=?new?User(); Users.copyUser(?source_user?);現(xiàn)在,我們可以在方法中直接 New:
Users.copyUser(?new?()?);當然,這個特性也結(jié)合了上面 Record 的特性。
因此,我們還可以這么寫:
Users.copyUser(?new?()?{?name?=?"WangPlus"?}?);嗯,語庋的改變需要一點時間來適應,但從長遠來看,依然是一種進步,會讓代碼更方便寫和讀。同時,這個特性,和 Var 會變成編程的兩個面,哪個更好用,看自己的習慣了。
3. 總結(jié)
總的來說,Dotnet 5.0 的變化還是有很多驚喜的。上面寫的,只是我們能比較容易感受到的部分,感受不到的部分,比方編譯的合理性、性能的優(yōu)化,GC的回收,做得都相當優(yōu)秀。
早轉(zhuǎn) 5.0 早好,對吧?
喜歡就來個三連,讓更多人因你而受益
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的再来说说我喜欢的 Dotnet 5.0 C# 9的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用identity+jwt保护你的we
- 下一篇: Layui宣布下线,不自禁的感叹一下,回