C# 可空類型(Nullable)的正確使用方式

本文使用 .NET 6(C# 10) 做示範

Nullable 的警告

    
public class User
{
    public string Id { get; set; } = null;
}
    

上面的程式碼在 null 上會有黃色的線條提示警告: Cannot convert null literal to non-nullable reference type

無法將 null 文字轉換為不可為 null 的參考類型?!什麼鬼?該怎麼讓這個警告消失?
很簡單,在文件最上方加入 #nullable disable 即可:
    
#nullable disable

public class User
{
    public string Id { get; set; } = null;
}
    

這樣就不會再出現警告了,解決!每天晚上 23:59 分準時發布新文章,我們明天見~

什麼是 Nullable ?

C# 8.0 推出了「可為 Null 的參考型別」(Nullable),並從 .NET 6(C# 10)開始預設啟用,只要變數出現空就會給予警告,目的是為了提醒我們可能是 Null ,盡量避免出現無效操作異常:
    
Unhandled exception. System.InvalidOperationException: Nullable object must have a value.
    

Nullable 的使用也很簡單,就是在型態後面加上一個問號,代表可以為空,看一下幾個範例:
    
int number1; // 不可為空,預設是 0
int number2 = 0; // 不可為空,預設是 0
int? number3 = null; // 可以為空

string str1 = null!; // 一定不會是空,告訴編譯器不用緊張,我自己處理
string str2 = string.Empty; // 初始值為空字串
string str3 = null; // 可以為空

List<int> list1 = null!; // 一定不會是空
List<int> list2 = new List<int>(); // 初始值為空集合
List<int>? list3 = null; // 可以為空
    


如果我們很確定他一定不會是 null ,又不想給予初始值,就可以使用 null! 安撫編譯器,讓他明白我們知道不會空,一切都在我們的掌控之中。

Nullable 的使用方式

    
int number1 = 1;
int? number2 = 2;
int ans = number1 + number2;
    


奇怪?上面這個哪裡錯了?數字加數字為什麼會出錯? Nullable 真難用,居然會出現錯誤訊息:
    
Cannot convert source type 'System.Nullable<int>' to target type 'int'
    

一開始遇到 Nullable 都會卡很久,這到底是什麼鬼?乾脆全部都用不可為空,讓 Nullable 坐冷板凳。

其實加了那個 Nullable 的問號,就會把他的類型用 Nullable 包起來,下面兩個語法是等效的:
    
int? number2 = 2;
    
    
System.Nullable<int> number2 = 2;
    

既然 int 被包了一層,那我們要使用的時候就需要把它拿出來,使用 .Value 就可以輕鬆解決:
	
int number1 = 1;
System.Nullable<int> number2 = 2; // int? number2 = 2;
int ans = number1 + number2.Value;
Console.WriteLine(ans); // 3
    

Nullable 好用之處

我們來看一個常見的範例,被除數除以除數,如果除數為 null (當然 0 也不能,這裡只是示範),則會拋出例外
    
int? dividend = 10;
int? divisor = null;
int quotient = dividend.Value / divisor.Value;
Console.WriteLine($"quotient = {quotient}");

/*
Unhandled exception. System.DivideByZeroException: Attempted to divide by zero.
*/
    

在 int 的 Nullable 中有以下幾種常見的方式用來解決這個問題:
    
// 如果 divisor 為 null,直接設定為 1
int dividendValue = dividend ?? 1;
// 嘗試取得 divisor 的值,如果為預設值,則設定為 1
int dividendValue = dividend.GetValueOrDefault(1); // 如果沒有傳入參數,則使用預設值(預設為 0)
// 如果 divisor 為 null,拋出 ArgumentNullException 例外,不處理
int dividendValue = dividend ?? throw new ArgumentNullException(nameof(dividend));
    

有這些語法糖,在操作上就非常容易。

參考資料:
Microsoft.Learn - Nullable reference types (C# reference)
Microsoft.Learn - Nullable value types (C# reference)
Microsoft.Learn - The history of C# - C# 8

留言