可為 null 的實數值型別 (c # 參考)

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

注意

C # 8.0 引進可為 null 的參考型別功能。 如需詳細資訊,請參閱 可為 null 的參考型別。 從 c # 2 開始可以使用可為 null 的實數值型別。

任何可為 null 的實值型別都是泛型結構的實例 System.Nullable<T> 。 您可以使用下列任何可交換形式的基礎類型來參考可為 null 的實數值型別 TNullable<T>T?

當您需要代表基礎實值型別的未定義值時,通常會使用可為 null 的實值型別。 例如,布林值或 bool 變數只能是 truefalse 。 不過,在某些應用程式中,變數值不能定義或遺失。 例如,資料庫欄位可能包含 truefalse ,或可能完全不包含任何值,也就是 NULLbool?在該案例中,您可以使用類型。

宣告與指派

因為實值型別可隱含轉換成對應的可為 null 實值型別,所以您可以將值指派給可為 null 實值型別的變數,就像您針對其基礎實值型別所做的一樣。 您也可以指派 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 之實值型別的預設值代表 null ,也就是其屬性會傳回的實例 Nullable<T>.HasValue false

檢查可為 null 實值型別的實例

從 c # 7.0 開始,您可以使用 is 運算子搭配型別模式來檢查可為 null 實值型別的實例 null ,並取出基礎型別的值:

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

您一律可以使用下列唯讀屬性來檢查並取得可為 null 實值型別變數的值:

下列範例 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 實值型別的變數 null ,而不使用 HasValue 屬性,如下列範例所示:

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 實值型別的值指派給不可為 null 的實值型別變數,您可能需要指定要指派的值來取代 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?

提起運算子

對應的可為 null 實值型別也支援預先定義的一元和二元 運算子 或實數值型別所支援的任何多載運算子 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 比較運算元的包含值。

如果兩個實值型別之間有 使用者定義的轉換 ,也可以在對應的可為 null 實值型別之間使用相同的轉換。

Box 處理和 Unbox 處理

可為 null 的實值型別的實例 T? 會以下列方式 裝箱

  • HasValue 傳回 false,則會產生 Null 參考。
  • 如果 HasValue 傳回 true ,則會將基礎實值型別的對應值 T 裝箱,而不是的實例 Nullable<T>

您可以將實數值型別的已裝箱值取消封裝 T 為對應的可為 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 實例。

如果您想要判斷某個實例是否屬於可為 null 的實值型別,請不要使用 Object.GetType 方法來取得 Type 要使用上述程式碼測試的實例。 當您 Object.GetType 在可為 null 的實值型別實例上呼叫方法時,實例就會被 封裝Object 。 當可為 null 實值型別的非 null 實例的裝箱相當於基礎類型值的裝箱時,會傳回 GetType Type 表示可為 null 實值型別之基礎型別的實例:

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

此外,請勿使用「 」運算子來判斷實例是否為可為 null 的實值型別。 如下列範例所示,您無法使用運算子來區別可為 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?

您可以使用下列範例中所示的程式碼,判斷實例是否為可為 null 的實值型別:

int? a = 14;
Console.WriteLine(IsOfNullableType(a));  // output: True

int b = 17;
Console.WriteLine(IsOfNullableType(b));  // output: False

bool IsOfNullableType<T>(T o)
{
    var type = typeof(T);
    return Nullable.GetUnderlyingType(type) != null;
}

注意

可為 null 的參考型別案例中,本節所述的方法不適用。

C# 語言規格

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

另請參閱