泛型程式設計中,如何為型別參數 T 的變數指定「預設值」?null 僅適用參考型別,實值型別(int、struct)不可為 null。C# 提供 default(T) 運算子,在編譯期依據 T 實際型別自動產生正確預設值,是泛型初始化的標準解法。
public class DefaultValueExample<T>
{
T _data = default(T); // 欄位初始化
public bool IsDefaultData()
{
T temp = default(T); // 區域變數初始化
return temp.Equals(_data);
}
public void SetData(T val) => _data = val;
}
var dv = new DefaultValueExample<int>();
Console.WriteLine(dv.IsDefaultData()); // True (_data = 0)
dv.SetData(100);
Console.WriteLine(dv.IsDefaultData()); // False
輸出:
Initial data: True Set data: False
| T 的分類 | 具體型別範例 | default(T) 結果 |
|---|---|---|
| 數值型別 | int, long, double, decimal, byte... | 0 (或 0.0) |
| 布林型別 | bool | false |
| 字元型別 | char | '\0' (U+0000) |
| 列舉型別 | enum E { A, B } | 0 (轉換為底層整數) |
| 參考型別 | class, interface, delegate, array, string | null |
| 可空值型別 | int?, Nullable<DateTime> | null (HasValue=false) |
| 結構體 | DateTime, Guid, 自訂 struct | 所有欄位遞迴 default(數值=0、參考=null) |
// 錯誤示範
T _data = null; // CS0403: 無法將 null 轉換為型別參數 T,因為它可能是不可為 null 的實值型別
編譯器不知道 T 會被具現化為何種型別,為了型別安全,禁止隱含 null 指派。
雖然 Nullable<T> (或 T?) 可儲存 null,但:
T,參考型別本身已可為 nullHasValue 檢查複雜度default(T) 統一處理所有分類,零成本、零認知負擔。
// 型別可推斷時,可省略型別參數
T _data = default; // 等同 default(T)
var temp = default; // 需有明確型別推斷上下文
適用於欄位初始化、區域變數宣告、方法預設參數等場合。
public class Cache<TKey, TValue>
{
private TValue _defaultValue = default; // 編譯期確定
public TValue GetOrDefault(TKey key)
{
if (_store.TryGetValue(key, out var val)) return val;
return _defaultValue; // 直接回傳,無需判斷 TValue 分類
}
}
default(T) 是 C# 泛型初始化的基石:
null 指派風險default 字面常數更簡潔編寫泛型程式碼時,永遠使用 default(T) 或 default 初始化型別參數變數,是專業 C# 開發者的標準習慣。