C# 8 - Nullable Reference Types 可空引用類型

在寫C#代碼的時候,你可能常常會遇到這個錯誤: session

 

但若是想避免NullReferenceException的發生,確實須要作不少麻煩的工做。 app

 

可空引用類型 Null Reference Type 

因此,C# 8的可空引用類型就出現了。 函數

C# 8可讓你在編譯時就避免null引用錯誤,它並非把null值從代碼裏移除了,而是它可讓你表達意圖。具體的作法就是你能夠告訴編譯器哪一個引用多是null的,而哪些引用不多是null ui

 

看下面這個例子: spa

O references 
PrintPerson(Person person) 
public static void 
Console . WriteLine(person.Name);

很顯然,咱們期待person這個參數它不能夠是null的。 orm

 

可是在C# 8以前,若是咱們這樣調用該方法,那麼在編譯時是不會報錯的: xml

null; 
Person person 
PrintPerson(person);

 

而若是運行程序,那麼結果就是: ci

Console . WriteLine(person . Name); 
class Person 
•son = null 
Exception Unhandled 
System.NullReferenceException: 'Object reference not set to an 
LIC 
LIC 
string Name { 
{ get; 
int 
Age 
get; 
set; 
set; 
instance of an object.' 
person was null. 
View Details Copy Details 
Exception Settings 
Start Live Share session...

 

打開null檢查 

而在Visual Studio 2019裏面(C# 8的項目),修改項目文件,添加null檢查以後: get

'<Project Sdk-"Microsoft.NET.Sdl<"> 
<PropertyGroup> 
<OutputType>Exe</OutputType> 
<Target Framework>netcoreapp3. R/ Target Framework> 
PropertyGroup> 
<PropertyGroup> 
PropertyGroup> 
</Project>

 

null; , 
Person person 
PrintPerson(Eä2Q);

這裏就會出現警告。 編譯器

 

例子: 

有兩個類,Person類的Address屬性的類型是另一個類: 

2 references 
public class Person 
O references 
{ get; set; } 
public string 
Name 
I reference 
Address { get; set; 
public Address 
I reference 
public class Address 
I reference 
public string Province { get; set; 
O references 
{ get; set; } 
public string

如今能夠看到,這些屬性都出現了波浪線的警告,若是咱們build一下這個項目,那麼也會出現不少警告: 

Show output from: Build 
' •n 'void printperson(person 
Rebuild All 
starte 
c: (30, 
1>Pro 
c: (31, 
1>Pro 
c: (24, 
1>Pro 
c: (25, 
1>Pro 
cs(ll, 
1>Pro 
cs(12, 
1>Pro 
n: 1 Appl — 
1>C0 
ne building 
Rebul 
23, 30, 31) 
23, 31, 27) 
23, 24, 27) 
24, 25, 31) 
29, 11, 33) 
25, 12, 31) 
warm 
warm 
warm 
warm 
warm 
warm 
d project: ConsoleÅppl, 
ng CS8618: 
ng CS8618: 
ng CS8618: 
ng CS8618: 
ng cs8600: 
ng CS8604: 
guy at 1 on: 
ble property ' 
ble proper 
ble proper 
ty 
ble proper 
ty 
Debug 
k-,y CPU 
ci ty' 
e 
Address' is 
s 'minitialized C n 
s 'minitializeå 
s 'minitializeå 
'minitialized C n 
for 
Consi der 
to non—null a 
1 ill 
r declaring the 
declaring the pr 
C n d declaring the pr 
r declaring the 
ble type 
property as null able 
operty as nullablæ 
operty as nullablæ 
property as null able 
Converting null lit al or possible null due 
\Cons01eÅppl 0\Conso e 
project "ConsoleÅppL c 
'Id All: 1

這是由於咱們把這兩個類的成員聲明稱了非null的引用類型,而我卻沒有對它們進行初始化。 

 

成員多是null 

若是我想讓這些成員能夠爲null(意圖上),那麼就須要把它們設置爲可null的(意圖),在類型後邊加上問號「?」便可: 

2 references 
public class Person 
O references 
{ get; 
public string? 
Name 
I reference 
public Address? Address { 
I reference 
public class Address 
I reference 
public string? Province { 
O references 
City 
public string? 
get; 
set; } 
get; set; 
get; set; 
set;

 

再次build項目以後,警告都沒有了: 

Show output from: Build 
Rebuild started: projec 
I >Cons01eÅppl — 
Rebuild All: 1 succeeded, 
ConsoleÅppl, 
gurati on: 
Debug kny CPU 
\Cons01eÅppl nso e 
0 1 ill

 

而後再看一下這個方法: 

O references 
Print(Person person) 
public static void 
Console . WriteLine(person.Name); 
Console . WriteLine( . Province) ;

這裏person.Address.Province有一個警告,是由於Address多是null 

 

能夠有幾種辦法把這個警告去掉,首先是使用null條件操做符: 

若是是Address是null的話,就輸出null 

或者,若是你確認Address屬性不會是null,那麼能夠在Address後添加一個歎號」!「,表示Address確定不是null 

Console .WriteLine(person .Address ! . Province) ;

這個歎號的做用僅僅是去掉了警告,它沒有改變任何運行時的情況,若是Addressnull,那麼這句話仍然會拋出NullReferenceException 

 

因此,只有確認咱們訪問的東西確定不是null的時候,才應該使用"!" 

 

成員不多是null 

下面我更改一下思路意圖,假設全部的成員都不可能爲null,那麼修改兩個類: 

類成員又出現了警告。 

 

而回到方法裏,我把歎號和問號都去掉以後,也不會出現警告了,由於它認爲全部的成員都不會是null了: 

可是還要記住,這個只是在編譯時進行的檢查,若是成員爲null,仍是會拋出異常的。這種操做對於運行時來講沒有任何改變。 

 

解決成員上出現的警告 

使用構造函數對成員初始化,能夠去掉這些警告: 

 

另一種辦法就是直接對屬性進行初始化: 

 

咱們仍是採用構造函數初始化的辦法吧。 

 

往構造函數裏傳遞null 

那麼往構造函數裏面傳遞null會出現什麼狀況呢?試一下: 

提示仍是比較智能的,有警告,它說沒法把null這個字面值轉化爲非null的引用類型。 

 

另外一種開啓nullable檢查的方式 

若是把老項目的項目文件直接添加如下內容: 

那麼項目在編譯的時候極可能出現大規模的問題。 

 

因此一點一點啓用nullable檢查是比較好的作法。 

首先我把項目文件恢復原狀,而後打開某個文件,在文件最上面添加如下內容: 

 

而後在文件的最下面添加: 

 

這樣的話,這個文件裏面全部的內容都開起了nullable檢查。 

或者,咱們也能夠只針對一段代碼進行檢查: 

相關文章
相關標籤/搜索