CodeGym /課程 /C# SELF /值型的 Nullable 類型

值型的 Nullable 類型

C# SELF
等級 14 , 課堂 0
開放

1. 前言

想像一下這種情境:你在程式裡存貓咪的資料。除了像年齡這種資訊,你還想存「沒資料」、「年齡未知」這種狀態。你或許會想用 0 來代表,但 0 其實是個有效的年齡啊。

int age = 0; // 貓的年齡。但 0 是什麼?小貓還是「未知」?

問題來了,int 只能存整數,沒辦法表達「沒資料」這種狀態。如果年齡是字串,還可以設 null。但數字就不行啦:

int age = null; // 錯誤! 不能把 null 指派給 int 變數

這是因為 值型(像 struct,例如 intdoubleDateTimebool)一定要有值。它們沒有「空」的狀態(不像參考型,null 就是沒有物件)。

生活中的例子:
有些工程師會用「特殊」數值來繞過這個限制,比如 -1int.MaxValue 代表「沒值」。但這樣很醜、很麻煩,也很危險:很容易把真的值跟假值搞混。

2. Nullable 類型:可以有 "null" 的型別

概念

如果讓一般的數字(或所有值型)也能存 null,會怎樣?
C# 用一個特別的包裝類 Nullable<T> 來實現。這個類可以存一個 T 型別的值,或什麼都沒有(也就是 null)。

語法

int? age = null; // 變數 age 可以是數字,也可以是 null
? 宣告 nullable 類型

C# 編譯器看到這種寫法,其實會當成:

Nullable<int> age = new Nullable<int>(); // 變數 age 沒有值

或者你想直接給值:

Nullable<int> age = new Nullable<int>(42); // age 裡面是 42

所以問號會把任何值型變成它的 nullable 版本:

  • int?(等同 Nullable<int>
  • double?
  • DateTime?
  • 還有其他 struct 都可以

常見 struct 的 Nullable 包裝

一般型別 Nullable 型別 寫法範例
int
int?
int? a = null;
double
double?
double? x = 3.14;
bool
bool?
bool? ok = null;
DateTime
DateTime?
DateTime? d = null;

你也可以寫長一點,用包裝類的寫法:


Nullable<int> pages = null;
        
長寫法

但寫 int? 比較短,也比較帥。

3. 怎麼用 nullable 類型

指派跟檢查

指派 null 跟參考型一樣簡單:

宣告跟指派

int? temperature = null;
temperature = 25;

檢查是不是 null

怎麼知道 nullable 型別裡有沒有值?

if (temperature != null)
{
    Console.WriteLine($"溫度:{temperature}");
}
else
{
    Console.WriteLine("沒有溫度資料");
}

Nullable 型別的屬性:.HasValue.Value

nullable 型別有兩個很重要的屬性:

  • .HasValue — 如果變數有值(不是 null),就回傳 true
  • .Value — 直接拿值(如果有,不然會丟例外)。
int? temperature = null;
if (temperature.HasValue) //不會丟例外!
{
    Console.WriteLine($"溫度:{temperature.Value}°C");
}
else
{
    Console.WriteLine("溫度未知");
}

這段程式會動:temperature 不是 null,它裡面包著 null。你隨時可以叫 Nullable 型別的 HasValue。但如果沒值還硬要拿 .Value,就會噴 InvalidOperationException。記得先檢查有沒有值!

簡化寫法

很多時候你直接用 nullable 變數,C# 會自己處理:

int? hours = null;
Console.WriteLine(hours); // 不會印東西(就是空的)
hours = 10;
Console.WriteLine(hours); // 印出 10

4. 運算跟 nullable 類型:算術、比較、型別轉換

運算:會發生什麼?

只要有一個運算元是 nullable,結果也是 nullable。
如果有一個運算元是 null,結果也會是 null

int? a = 5;
int? b = null;
int? sum = a + b; // sum == null

int? c = 10;
int? d = 15;
int? total = c + d; // total == 25

比較運算

你可以拿 nullable 類型跟一般數字比大小:

int? score = null;
if (score > 0) Console.WriteLine("很棒的結果!");
else Console.WriteLine("沒有結果"); // 會跑這裡

如果 score 是 null,score > 0 會是 false

明確跟隱含型別轉換

  • 從一般型別轉 nullable:自動轉。
  • 從 nullable 轉一般型別:只有不是 null 才行(不然會丟例外)。
int? x = 3;
int y = x.Value; // OK,只要 x 不是 null

// 隱含轉換
int? z = y;

5. Nullable 跟方法:參數跟回傳值

回傳 nullable 值

如果方法不一定能回傳結果,可以用 nullable 型別當回傳值:

// 方法根據登入找使用者,找到就回傳年齡,沒找到就回傳 null
int? FindUserAge(string login)
{
    // ... 這裡是搜尋邏輯
    return null; // 沒找到
}

Nullable 參數

你也可以讓參數是 nullable,這樣就很明確:「可能有,也可能沒有」。

void PrintTemperature(int? temp)
{
    if (temp == null)
        Console.WriteLine("溫度未知");
    else
        Console.WriteLine($"溫度:{temp} 度");
}
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION