與其他的本地方法不同,靜態的本地方法無法捕獲任何本地狀態量。
直接看例子:
這段代碼里有兩個本地方法,他們分別對實例的一個字段和方法里的一個本地變量進行了修改操作,也就是捕獲並更新了本地的狀態。
其運行結果是:

可以看到類的成員字段和方法本地變量的狀態都被這兩個本地方法修改了。。
但是很多情況下,你並不希望類的實例字段和方法本地變量的值被捕獲或修改。在C# 8里面,你可以使用靜態本地方法來達到這個目的。
其做法很簡單,就是在原來這兩個本地方法前面加上static關鍵字即可:
可以看到程序報錯了,這是因為靜態本地方法是不可以訪問和捕獲實例的狀態的,包括實例成員和方法本地變量。
針對第一個本地方法,我直接把更新本地變量的語句去掉:
而針對第二個本地方法,如果你真的想修改實例成員的狀態,那么就需要把成員改為靜態的:
其運行結果是:

優點
C# 8的這個特性對可讀性其實沒有特別大的幫助,但是它卻可以防止本地方法捕獲實例狀態,在一些情況下,這對性能有很大的幫助。
Disposable ref Structs
C# 7.2 里面出現了ref struct,但是它的缺點就是不可以實現接口。
看這個例子:
這個struct里面包含了一個不安全(unsafe)資源,當我用完之后,這個資源是需要被清理掉的。
在C# 8之前,我們無法針對這個struct使用using語句,因為這個struct無法實現IDisposable接口。
但是從C# 8開始,ref struct無需實現IDisposable接口也可以使用using語句或者using聲明,只要它提供了適當的方法即可。如下圖:
然后我們就可以使用using語句了:
或者using聲明:
只讀struct成員
從C# 8開始,我們可以在struct的成員上使用readonly修飾符。
為struct的成員添加readonly修飾符就表示告訴編譯器和開發者該成員不可以修改struct的狀態。
看下面這個例子:
這里的ToString()方法不會修改Point這個struct的狀態,所以我們可以在該方法上添加readonly修飾符來表示其只讀:
但是這里會出現警告,因為 ToString 訪問了未標記為 readonly 的 Distance 屬性。也就是需要創建防御性副本時,編譯器會發出警告。
由於Distance屬性不會修改狀態,所以可以在它前邊加上readonly修飾符以修復此警告:
請注意,readonly 修飾符對於只讀屬性是必須要添加的。 編譯器會假設 get 訪問器可以修改狀態;所以必須顯式聲明 readonly。
但是自動實現的屬性則是一個例外;編譯器將所有自動實現的 Getter 視為 readonly,因此,此處無需向 X 和 Y 屬性添加 readonly 修飾符。
如果我在該struct里面再添加一個修改狀態的方法:
由於該方法確實修改了struct的狀態,所以如果在該方法上再加上readonly修飾符的話,編譯器就會報錯。
而如果我把readonly修飾符去掉的話,那么就不會報錯了:
在C#里面,類型可以分為托管類型和非托管類型。在之前的.NET版本中,只有內置的值類型、枚舉類型和僅包含非托管類型成員的struct等這些類型才可以是非托管類型。其中內置的值類型有:
-
byte
-
int
-
char
-
float
-
bool
-
…
而構造類型(指包含至少一個類型參數的類型)不能為非托管類型。
看下面這個泛型struct:
在C# 7里,無論這里的T是int還是object,該類型都不可以是非托管類型,即使T是一個非托管類型。
而在C# 8里,如果構造類型的所有類型參數都是非托管類型的,那么這個構造類型就是非托管的。
所以Coords<int> 類型在 C# 8.0 及更高版本中是非托管類型。但是Coords<object>仍然是托管的。
Null 合並賦值
看例子。
在C# 8之前,我們可以通過如下代碼來保證numbers被初始化:
但是從C# 8開始,我們可以更簡單的表達我們的意思:
這個特性帶來的好處是,在變量名不是特別短小精悍的情況下,會少打很多字符。
內插逐字字符串的增強功能
C# 8里,針對內插逐字字符串的功能做了一點點增強。
在C# 8之前,這樣寫是沒毛病的:
但是這樣寫就不行:
但是從C# 8開始,兩種寫法都是正確的:
都不會報錯了。