共用方式為


可為 Null 的值類型 (C# 參考)

可為 Null 的實值型別T? 代表其基礎實值型別T 的所有值,以及額外的 Null 值。 例如,您可以將下列三個值中的任何一個指派給 bool? 變數:truefalsenull。 底層的值型別 T 本身不能是可空值型別。

C# 語言參考資料記錄了 C# 語言最新版本。 同時也包含即將推出語言版本公開預覽功能的初步文件。

文件中標示了語言最近三個版本或目前公開預覽版中首次引入的任何功能。

小提示

欲查詢某功能何時首次在 C# 中引入,請參閱 C# 語言版本歷史的條目。

任何可為 Null 的實值型別都是泛型 System.Nullable<T> 結構的執行個體。 您可以使用下列任一可互換形式,參考具有基礎型別 T 的可為 Null 實值型別:Nullable<T>T?

通常,當你需要表示底層值型別的未定義值時,會使用可空值型別。 例如,布林值或 bool、變數只能是 truefalse。 不過,在某些應用程式中,變數值可能未定義或遺失。 例如,資料庫欄位可能包含 truefalse,或完全沒有值,也 NULL就是 。 您可以在該情節中使用 bool? 型別。

宣告與指派

由於一個值型別隱含可轉換為對應的可空值型別,你可以像對底層值型別的變數指派一個可空值型別的變數值一樣。 您也可以指派 null 值。 例如:

double? pi = 3.14;
char? letter = 'a';

int m2 = 10;
int? m = m2;

bool? flag = null;

// An array of a nullable value type:
int?[] arr = new int?[10];

可空值類型的預設值代表 null。 這是一個性質 Nullable<T>.HasValue 回傳 false的實例。

檢查可為 Null 實值型別的執行個體

要檢查可空值型別的 null 實例並取得底層型別的值,請使用 is 帶有型態模式的運算子

int? a = 42;
if (a is int valueOfA)
{
    Console.WriteLine($"a is {valueOfA}");
}
else
{
    Console.WriteLine("a does not have a value");
}
// Output:
// a is 42

你也可以使用以下唯讀屬性來檢查並取得可空值型態變數的值:

以下範例使用該 HasValue 屬性來檢查變數在顯示前是否包含該值:

int? b = 10;
if (b.HasValue)
{
    Console.WriteLine($"b is {b.Value}");
}
else
{
    Console.WriteLine("b does not have a value");
}
// Output:
// b is 10

您也可以如以下範例所示,使用 null 而非使用 HasValue 屬性,比較可為 Null 實值型別的變數:

int? c = 7;
if (c != null)
{
    Console.WriteLine($"c is {c.Value}");
}
else
{
    Console.WriteLine("c does not have a value");
}
// Output:
// c is 7

從可為 Null 實值型別轉換至基礎型別

如果你想將可空值型別的值分配給不可空值型態變數,可能需要指定要指派的值來取代 null。 用 空聚合算子 ?? 來做這件事。 你也可以用這個 Nullable<T>.GetValueOrDefault(T) 方法達到同樣的目的:

int? a = 28;
int b = a ?? -1;
Console.WriteLine($"b is {b}");  // output: b is 28

int? c = null;
int d = c ?? -1;
Console.WriteLine($"d is {d}");  // output: d is -1

如果您想要使用基礎實值型別的預設值取代 null,請使用 Nullable<T>.GetValueOrDefault() 方法。

如下列範例所示,您也可以明確地將可為 Null 的實值型別轉換成不可為 Null 的型別:

int? n = null;

//int m1 = n;    // Doesn't compile
int n2 = (int)n; // Compiles, but throws an exception if n is null

在執行階段,若可為 Null 實值型別的值為 null,則明確轉換會擲回 InvalidOperationException

不可為 Null 的實值型別 T 會隱含轉換成對應的可為 Null 實值型別 T?

增益運算子

可空值型別 T? 支援預先定義的一元與二元 運算子 ,或值型別 T 所支援的任何超載運算子。 這些運算子,也稱為提升運算子,若其中一個或兩個運算元為 null,則返回 null 。 否則,運算子會利用其運算元的內含值來計算結果。 例如:

int? a = 10;
int? b = null;
int? c = 10;

a++;        // a is 11
a = a * c;  // a is 110
a = a + b;  // a is null

注意

針對 bool? 型別,預先定義的 &| 運算子不會遵循本節中描述的規則:即使其中一個運算元為 null,運算子評估的結果也可能為非 Null。 如需詳細資訊,請參閱布林值邏輯運算子一文的可為 Null 的布林值邏輯運算子一節。

對於比較算子<><=>=,若一個或兩個運算元為 null,則結果為 false。 否則,則比較包含的運算元值。 不要假設因為某個比較(例如) <=會返回 false,而相反的比較(>)則返回 true。 下列範例會顯示 10

  • 既不大於也不等於 null
  • 也不小於 null
int? a = 10;
Console.WriteLine($"{a} >= null is {a >= null}");
Console.WriteLine($"{a} < null is {a < null}");
Console.WriteLine($"{a} == null is {a == null}");
// Output:
// 10 >= null is False
// 10 < null is False
// 10 == null is False

int? b = null;
int? c = null;
Console.WriteLine($"null >= null is {b >= c}");
Console.WriteLine($"null == null is {b == c}");
// Output:
// null >= null is False
// null == null is True

對於 等號算子==,若兩個運算元皆為 null,則結果為 true。 若只有一個運算元為 null,則結果為 false。 否則,則比較包含的運算元值。

對於 不等式算子!=,若兩個運算元皆為 null,則結果為 false。 若只有一個運算元為 null,則結果為 true。 否則,則比較包含的運算元值。

若存在兩種值類型間的 使用者定義轉換 ,則相同的轉換也可用於相應的可空值類型。

Box 處理和 Unbox 處理

當你將一個可空值型別T?的實例框起來時,適用以下規則:

  • 若返回 HasValuefalse,則盒裝操作回傳空參考。
  • HasValue 返回 true,則 boxing 運算會將底層值類型 T的對應值 打框,而非 的 Nullable<T>實例。

如下列範例所示,您可以將實值型別為 T 的 boxed 值 unbox 為對應的可為 Null 實值型別 T?

int a = 41;
object aBoxed = a;
int? aNullable = (int?)aBoxed;
Console.WriteLine($"Value of aNullable: {aNullable}");

object aNullableBoxed = aNullable;
if (aNullableBoxed is int valueOfA)
{
    Console.WriteLine($"aNullableBoxed is boxed int: {valueOfA}");
}
// Output:
// Value of aNullable: 41
// aNullableBoxed is boxed int: 41

如何識別可為 Null 的實值型別

下列範例示範如何判斷 System.Type 執行個體是否代表建構可為 Null 的實值型別,也就是,System.Nullable<T> 型別具有指定的型別參數 T

Console.WriteLine($"int? is {(IsNullable(typeof(int?)) ? "nullable" : "non nullable")} value type");
Console.WriteLine($"int is {(IsNullable(typeof(int)) ? "nullable" : "non-nullable")} value type");

bool IsNullable(Type type) => Nullable.GetUnderlyingType(type) != null;

// Output:
// int? is nullable value type
// int is non-nullable value type

如範例所示,您使用 typeof 運算子來建立 System.Type 執行個體。

如果你想判斷一個實例是否屬於可空值型別,就不要用 Object.GetType 前面的程式碼來讓 Type 實例測試。 當您在可為 Null 的實值型別執行個體上呼叫 Object.GetType 方法時,該執行個體會 boxed 處理為 Object。 因為對可空值類型的非空實例進行封箱等同於對底層型別的值進行封裝,因此 GetType 回傳一個 Type 代表可空值型別底層型別的實例:

int? a = 17;
Type typeOfA = a.GetType();
Console.WriteLine(typeOfA.FullName);
// Output:
// System.Int32

此外,請勿使用 is 運算子,來判斷某個執行個體是否屬於可為 Null 的實值型別。 如下範例所示,你無法透過使用運算 is 子區分可空值值類型實例的類型與其底層型別實例的類型:

int? a = 14;
if (a is int)
{
    Console.WriteLine("int? instance is compatible with int");
}

int b = 17;
if (b is int?)
{
    Console.WriteLine("int instance is compatible with int?");
}
// Output:
// int? instance is compatible with int
// int instance is compatible with int?

相反地,請使用 Nullable.GetUnderlyingType 第一個範例中的方法和 typeof 運算子來檢查某個實例是否屬於可空值型別。

注意

本節所述的方法不適用於 可空的參考型別

C# 語言規格

如需詳細資訊,請參閱 C# 語言規格的下列幾節:

另請參閱