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


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

 

但如果想避免NullReferenceException的發生,確實需要做很多麻煩的工作。 

 

可空引用類型 Null Reference Type 

所以,C# 8的可空引用類型就出現了。 

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

 

看下面這個例子: 

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

很顯然,我們期待person這個參數它不可以是null的。 

 

但是在C# 8之前,如果我們這樣調用該方法,那么在編譯時是不會報錯的: 

null; 
Person person 
PrintPerson(person);

 

而如果運行程序,那么結果就是: 

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檢查之后: 

'<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檢查。 

或者,我們也可以只針對一段代碼進行檢查: 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM