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

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

注意

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

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

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

宣告與指派

因為實值型別可隱含轉換成對應的可為 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 ,也就是其屬性 false 會傳回的實例 Nullable<T>.HasValue

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

從 c # 7.0 開始,您可以使用 運算子搭配型別模式來檢查可為 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

如果您想要使用基礎數值型別的 預設 值來取代 ,請使用 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 的實值型別值為,明確的轉換 InvalidOperationExceptionnull 擲回。

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

提起運算子

對應的可為 null 實值型 T? 別也支援預先定義的一元和二元運算子或實數值型別 所支援的任何多載運算子。 如果一或兩個運算元都是,則這些運算子(也稱為 提升運算子)會產生 ; 否則,運算子會 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? 別的實例會以下列方式 T?

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

您可以將實數值型別 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 的實值型別,也就是具有指定型別參數 TSystem.Nullable<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 運算子來建立 實例。

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

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

此外,請勿使用「 」運算子來判斷實例是否為可為 null 的實值型別。 如下列範例所示,您無法使用 is 運算子來區別可為 null 的實值型別實例及其基礎型別實例的類型:

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運算子的 Nullable.GetUnderlyingType 來檢查實例是否為可為 null 的實值型別。

注意

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

C# 語言規格

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

另請參閱