首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 可為 Null 的實值型別:Nullable<T> 語法、HasValue/Value、巢狀泛型限制

     編輯:關於C語言

前言

實值型別 (int、double、bool、DateTime、struct) 預設不可為 null。C# 2.0 引入 Nullable<T> 結構與 ? 語法糖,讓實值型別能表達「無值」狀態。本文詳細說明宣告、核心屬性、運算規則、巢狀限制與實務模式。

宣告語法


// 完整泛型語法
Nullable nullableInt = null;
Nullable nullableDouble = 3.14;

// 語法糖 (慣用)
int? myInt = null;
int? myInt2 = 42;
double? myDouble = 3.14;
bool? flag = null;
DateTime? birthDate = null;

// 結構體也適用
struct Point { public int X, Y; }
Point? nullablePoint = null;

核心結構:Nullable<T> 內部定義


public struct Nullable where T : struct
{
    private readonly bool _hasValue;
    private readonly T _value;
    
    public bool HasValue => _hasValue;
    public T Value => _hasValue ? _value : throw new InvalidOperationException();
    
    public T GetValueOrDefault() => _value;
    public T GetValueOrDefault(T defaultValue) => _hasValue ? _value : defaultValue;
    
    // 隱含/顯式轉換運算子...
}

關鍵屬性與方法

成員說明範例
HasValue是否有值 (true/false)int? x = null; x.HasValue == false
Value取得值 (無值時拋出例外)int? x = 5; x.Value == 5
GetValueOrDefault()取得值或預設值 (不拋出例外)int? x = null; x.GetValueOrDefault() == 0
GetValueOrDefault(T)取得值或指定預設值int? x = null; x.GetValueOrDefault(-1) == -1

運算規則:提升運算


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

// 算術運算:任一運算元為 null → 結果為 null
int? sum = a + b;      // null
int? diff = a - c;     // 5
int? prod = a * c;     // 50
int? quot = a / c;     // 2

// 比較運算:任一為 null → 結果為 false (除 != 外)
bool eq = (a == b);    // false (非 true)
bool ne = (a != b);    // true
bool lt = (a < c);     // false
bool gt = (a > c);     // true

// 邏輯運算 (bool?)
bool? x = true;
bool? y = null;
bool? z = false;

bool? and = x & y;     // null (三值邏輯)
bool? or = y | z;      // null
bool? not = !y;        // null

巢狀泛型限制:Nullable<Nullable<T>> 禁止


// ❌ 編譯錯誤 CS0453: 型別引數必須是非可為 Null 的實值型別
Nullable> nested = null;  
int?? doubleNullable = null;  // 語法糖也禁止

原因:Nullable<T> where T : struct 限制,而 Nullable<T> 本身是 struct,但被視為「可為 Null 的型別」,不滿足條件。

實務模式

1. 資料庫 NULL 對應


public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int? Age { get; set; }        // 對應 DB INT NULL
    public DateTime? LastLogin { get; set; }  // 對應 DB DATETIME NULL
    public decimal? Salary { get; set; }
}

2. 選擇性參數


public void Search(string keyword, int? pageSize = null, int? pageIndex = null)
{
    int size = pageSize.GetValueOrDefault(20);
    int index = pageIndex.GetValueOrDefault(0);
    // ...
}

3. 三狀態邏輯


bool? userConsent = null;  // null=未詢問, true=同意, false=拒絕

if (userConsent == true) { /* 同意 */ }
else if (userConsent == false) { /* 拒絕 */ }
else { /* 顯示同意對話框 */ }

4. 安全存取模式


// 模式 1: HasValue 檢查
if (nullableInt.HasValue) 
    Console.WriteLine(nullableInt.Value);

// 模式 2: GetValueOrDefault
Console.WriteLine(nullableInt.GetValueOrDefault(0));

// 模式 3: ?? 空合併運算子 (最推薦)
Console.WriteLine(nullableInt ?? 0);

// 模式 4: 模式比對 (C# 7+)
if (nullableInt is int value) 
    Console.WriteLine(value);
else 
    Console.WriteLine("無值");

裝箱行為特殊規則


int? a = 42;
int? b = null;

object boxedA = a;  // 裝箱為 int (非 Nullable!)
object boxedB = b;  // 裝箱為 null 參考

Console.WriteLine(boxedA.GetType());  // System.Int32
Console.WriteLine(boxedB);            // null

// 解封箱
int unboxedA = (int)boxedA;     // 正常
// int unboxedB = (int)boxedB;   // NullReferenceException
int? unboxedB = (int?)boxedB;   // 正常,結果為 null

總結

Nullable<T> (語法糖 T?) 讓實值型別獲得「無值」表達能力。核心在於 HasValue/Value 雙屬性設計、提升運算規則、?? 空合併運算子配合。禁止巢狀 Nullable<Nullable<T>> 簡化型別系統。資料庫映射、選擇性參數、三狀態邏輯是主要應用場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved