使用可為 Null 的類型 (C# 程式設計手冊)
可為 Null 的型別可以代表基礎型別的所有值,也可以代表另一個 null 值。 您可以使用下列其中一種方法宣告可為 Null 的型別:
System.Nullable<T> variable
-或-
T? variable
T 是可為 Null 之型別的基礎型別。 T 可以是任何實值型別,包括 struct ,它不能是參考型別。
何時該使用可為 null 的型別,可舉一般的布林變數為例,這種變數有兩個可能的值:true 和 false。 但沒有值可以代表「未定義」。 在許多設計程式的應用程式中,特別是資料庫互動的程式,變數有可能是以未定義的狀態存在。 例如,資料庫中的某個欄位可能包含 true 或 false 值,但也可能不包含任何值。 同樣地,參考型別可以設定為 null 表示其並非初始化的。
由於這些值的性質不同,就需要在程式上另做設計,包括使用其他變數存放狀態資訊、使用特殊值等等。 可為 null 的型別修飾詞能夠讓 C# 建立表示未定義之值的實值型別 (Value Type) 變數。
可為 Null 的型別範例
任何實值型別都可以當做可為 null 的型別的基礎, 例如:
int? i = 10;
double? d1 = 3.14;
bool? flag = null;
char? letter = 'a';
int?[] arr = new int?[10];
可為 Null 的型別成員
可為 null 之型別的每個執行個體 (Instance) 有兩個公用唯讀屬性:
HasValue
HasValue 屬於 bool 型別。 當變數包含非 null 的值時,該屬性會設定為 true。
Value
Value 的型別與基礎型別相同。 如果 HasValue 為 true,Value 會包含有意義的值。 如果 HasValue 為 false,存取 Value 將會擲回 InvalidOperationException。
在這個範例中,會先使用 HasValue 成員測試變數是否包含值,然後才會嘗試顯示該值。
int? x = 10;
if (x.HasValue)
{
System.Console.WriteLine(x.Value);
}
else
{
System.Console.WriteLine("Undefined");
}
也可使用下列範例完成測試值的作業:
int? y = 10;
if (y != null)
{
System.Console.WriteLine(y.Value);
}
else
{
System.Console.WriteLine("Undefined");
}
明確轉換
您可以明確使用轉型或使用 Value 屬性,將可為 null 的型別轉換成標準型別。 例如:
int? n = null;
//int m1 = n; // Will not compile.
int m2 = (int)n; // Compiles, but will create an exception if n is null.
int m3 = n.Value; // Compiles, but will create an exception if n is null.
如果在兩資料型別之間定義了使用者定義轉換,這兩個資料型別的可為 Null 的型別版本也可以使用該轉換。
隱含轉換
可為 Null 的型別 (Nullable Type) 可使用 null 關鍵字設為 null,如下列範例所示:
int? n1 = null;
從一般型別轉換成可為 null 的型別是隱含轉換。
int? n2;
n2 = 10; // Implicit conversion.
運算子
可為 Null 的型別也可以使用預先定義的一元和二元運算子,以及現有實值型別的任何使用者定義運算子。 如果運算元都是 null,這些運算子就會產生 null 值,否則運算子會使用所包含的值計算結果。 例如:
int? a = 10;
int? b = null;
a++; // Increment by 1, now a is 11.
a = a * 10; // Multiply by 10, now a is 110.
a = a + b; // Add b, now a is null.
使用可為 Null 的型別執行比較時,如果其中一個可為 Null 的型別值為 Null,但是其他的值不為 Null,則除了 != (不等於) 以外,其他所有比較都會評估為 false。 此時,請勿因為特定的比較傳回 false,因而認定其他相反的情況就會傳回 true。 在下列範例中,10 不會大於、小於或等於 Null。 只有 num1 != num2 評估為 true。
int? num1 = 10;
int? num2 = null;
if (num1 >= num2)
{
Console.WriteLine("num1 is greater than or equal to num2");
}
else
{
// This clause is selected, but num1 is not less than num2.
Console.WriteLine("num1 >= num2 returned false (but num1 < num2 also is false)");
}
if (num1 < num2)
{
Console.WriteLine("num1 is less than num2");
}
else
{
// The else clause is selected again, but num1 is not greater than
// or equal to num2.
Console.WriteLine("num1 < num2 returned false (but num1 >= num2 also is false)");
}
if (num1 != num2)
{
// This comparison is true, num1 and num2 are not equal.
Console.WriteLine("Finally, num1 != num2 returns true!");
}
// Change the value of num1, so that both num1 and num2 are null.
num1 = null;
if (num1 == num2)
{
// The equality comparison returns true when both operands are null.
Console.WriteLine("num1 == num2 returns true when the value of each is null");
}
/* Output:
* num1 >= num2 returned false (but num1 < num2 also is false)
* num1 < num2 returned false (but num1 >= num2 also is false)
* Finally, num1 != num2 returns true!
* num1 == num2 returns true when the value of each is null
*/
兩個皆為 Null 之可為 Null 的型別進行相等比較時,評估結果將會是 true。
?? 運算子
?? 運算子會定義當可為 null 的型別指派給不可為 null 的型別時,要傳回的預設值。
int? c = null;
// d = c, unless c is null, in which case d = -1.
int d = c ?? -1;
這個運算子也可以搭配多個可為 null 的型別使用。 例如:
int? e = null;
int? f = null;
// g = e or f, unless e and f are both null, in which case g = -1.
int g = e ?? f ?? -1;
bool?type
可為 null 的 bool? 型別可包含三種不同的值:true、false 和 null。 如需從 bool? 轉換為 bool 的詳細資訊,請參閱 如何:從 bool? 安全轉型到 bool (C# 程式設計手冊)。
可為 Null 的布林值就像 SQL 中使用的布林值變數型別。 若要確保 & 所產生的結果和 | 運算子與 SQL 中三個值的布林型別一致,提供下列預先定義的運算子:
bool? operator &(bool? x, bool? y)
bool? operator |(bool? x, bool? y)
這些運算子的結果列於下表:
X |
y |
x&y |
x|y |
---|---|---|---|
true |
true |
true |
true |
true |
false |
false |
true |
true |
null |
null |
true |
false |
true |
false |
true |
false |
false |
false |
false |
false |
null |
false |
null |
null |
true |
null |
true |
null |
false |
false |
null |
null |
null |
null |
null |