C# 8 - Nullable Reference Types 可空引用類型
從C# 8 開始,本地方法就可以是靜態(tài)的了。
與其他的本地方法不同,靜態(tài)的本地方法無(wú)法捕獲任何本地狀態(tài)量。
直接看例子:
這段代碼里有兩個(gè)本地方法,他們分別對(duì)實(shí)例的一個(gè)字段和方法里的一個(gè)本地變量進(jìn)行了修改操作,也就是捕獲并更新了本地的狀態(tài)。
其運(yùn)行結(jié)果是:
可以看到類的成員字段和方法本地變量的狀態(tài)都被這兩個(gè)本地方法修改了。。
但是很多情況下,你并不希望類的實(shí)例字段和方法本地變量的值被捕獲或修改。在C# 8里面,你可以使用靜態(tài)本地方法來(lái)達(dá)到這個(gè)目的。
其做法很簡(jiǎn)單,就是在原來(lái)這兩個(gè)本地方法前面加上static關(guān)鍵字即可:
可以看到程序報(bào)錯(cuò)了,這是因?yàn)殪o態(tài)本地方法是不可以訪問(wèn)和捕獲實(shí)例的狀態(tài)的,包括實(shí)例成員和方法本地變量。
針對(duì)第一個(gè)本地方法,我直接把更新本地變量的語(yǔ)句去掉:
而針對(duì)第二個(gè)本地方法,如果你真的想修改實(shí)例成員的狀態(tài),那么就需要把成員改為靜態(tài)的:
其運(yùn)行結(jié)果是:
C# 8的這個(gè)特性對(duì)可讀性其實(shí)沒(méi)有特別大的幫助,但是它卻可以防止本地方法捕獲實(shí)例狀態(tài),在一些情況下,這對(duì)性能有很大的幫助。
C# 7.2 里面出現(xiàn)了ref struct,但是它的缺點(diǎn)就是不可以實(shí)現(xiàn)接口。
看這個(gè)例子:
這個(gè)struct里面包含了一個(gè)不安全(unsafe)資源,當(dāng)我用完之后,這個(gè)資源是需要被清理掉的。
在C# 8之前,我們無(wú)法針對(duì)這個(gè)struct使用using語(yǔ)句,因?yàn)檫@個(gè)struct無(wú)法實(shí)現(xiàn)IDisposable接口。
但是從C# 8開始,ref struct無(wú)需實(shí)現(xiàn)IDisposable接口也可以使用using語(yǔ)句或者using聲明,只要它提供了適當(dāng)?shù)姆椒纯?。如下圖:
然后我們就可以使用using語(yǔ)句了:
或者using聲明:
從C# 8開始,我們可以在struct的成員上使用readonly修飾符。
為struct的成員添加readonly修飾符就表示告訴編譯器和開發(fā)者該成員不可以修改struct的狀態(tài)。
看下面這個(gè)例子:
這里的ToString()方法不會(huì)修改Point這個(gè)struct的狀態(tài),所以我們可以在該方法上添加readonly修飾符來(lái)表示其只讀:
但是這里會(huì)出現(xiàn)警告,因?yàn)?span id="fu8ihs5fyo3" class="TextRun BCX0 SCXO67251957" lang="EN-US" xml:lang="EN-US" data-contrast="auto"> ToString 訪問(wèn)了未標(biāo)記為 readonly 的 Distance 屬性。也就是需要?jiǎng)?chuàng)建防御性副本時(shí),編譯器會(huì)發(fā)出警告。
由于Distance屬性不會(huì)修改狀態(tài),所以可以在它前邊加上readonly修飾符以修復(fù)此警告:
請(qǐng)注意,readonly 修飾符對(duì)于只讀屬性是必須要添加的。 編譯器會(huì)假設(shè) get 訪問(wèn)器可以修改狀態(tài);所以必須顯式聲明 readonly。
但是自動(dòng)實(shí)現(xiàn)的屬性則是一個(gè)例外;編譯器將所有自動(dòng)實(shí)現(xiàn)的 Getter 視為 readonly,因此,此處無(wú)需向 X 和 Y 屬性添加 readonly 修飾符。
如果我在該struct里面再添加一個(gè)修改狀態(tài)的方法:
由于該方法確實(shí)修改了struct的狀態(tài),所以如果在該方法上再加上readonly修飾符的話,編譯器就會(huì)報(bào)錯(cuò)。
而如果我把readonly修飾符去掉的話,那么就不會(huì)報(bào)錯(cuò)了:
在C#里面,類型可以分為托管類型和非托管類型。在之前的.NET版本中,只有內(nèi)置的值類型、枚舉類型和僅包含非托管類型成員的struct等這些類型才可以是非托管類型。其中內(nèi)置的值類型有:
byte
int
char
float
bool
…
而構(gòu)造類型(指包含至少一個(gè)類型參數(shù)的類型)不能為非托管類型。
看下面這個(gè)泛型struct:
在C# 7里,無(wú)論這里的T是int還是object,該類型都不可以是非托管類型,即使T是一個(gè)非托管類型。
而在C# 8里,如果構(gòu)造類型的所有類型參數(shù)都是非托管類型的,那么這個(gè)構(gòu)造類型就是非托管的。
所以Coords<int> 類型在 C# 8.0 及更高版本中是非托管類型。但是Coords<object>仍然是托管的。
看例子。
在C# 8之前,我們可以通過(guò)如下代碼來(lái)保證numbers被初始化:
但是從C# 8開始,我們可以更簡(jiǎn)單的表達(dá)我們的意思:
這個(gè)特性帶來(lái)的好處是,在變量名不是特別短小精悍的情況下,會(huì)少打很多字符。
C# 8里,針對(duì)內(nèi)插逐字字符串的功能做了一點(diǎn)點(diǎn)增強(qiáng)。
在C# 8之前,這樣寫是沒(méi)毛病的:
但是這樣寫就不行:
但是從C# 8開始,兩種寫法都是正確的:
都不會(huì)報(bào)錯(cuò)了。