null,一個值得尊敬的資料標識。一般來說,null 表示空型別,也就是「什麼都沒有」,但「什麼都沒有」不代表「什麼都不是」。實際上,null 如此重要,在 JavaScript 中作為 5 種基本原始型別之一;在 .NET 中同樣表現出重要性。
務必澄清:null 不等同於 0、""、string.Empty 等通常意義上的「零」值。 null 擁有實實在在的意義——標識變數參考的一種狀態,表示「沒有參考任何物件實例」,既不是 Object 實例,也不是 User 實例,只是一個空參考。
null 表示一個物件參考是無效的。作為參考型別變數的預設值,null 是針對指標(參考)而言的,專屬於參考型別變數,表示「宣告但未初始化」的狀態:
object obj = null; // obj 僅是保存在執行緒堆疊上的參考指標,未指向任何有效實例
答案是:有區別,主要體現在編譯器檢查上。
// 編譯器偵測錯誤:使用未賦值變數 obj
// object obj;
// 編譯器理解為執行了初始化操作,不引發編譯時錯誤
object obj = null;
if (obj == null)
{
// 執行時拋出 NullReferenceException 異常
Console.WriteLine(obj.ToString());
}
反編譯為 IL 可見差異:前者無額外操作;後者透過 ldnull 指令推進空參考到評估堆疊,stloc 儲存空參考。
一直以來,null 是參考型別專屬。對值類型進行 null 操作會在編譯期拋錯。自 .NET 2.0 起,System.Nullable<T> 打破此限制:
int? i = null; // 語法糖,等同於 Nullable<int> i = null;
if (i == null) { Console.WriteLine("i is null."); }
Nullable<Boolean> 包含 true、false、null。Nullable<T> 本質仍是 struct(值類型),實例配置在執行緒堆疊。其定義包含 hasValue 與 value 兩個核心欄位,建構函數將值賦給 value 並設 hasValue = true。IL 表示為 valuetype [mscorlib]System.Nullable`1<int32>。
Nullable<Nullable<T>>)。Nullable<T> 與 T? 等效。GetType 回傳型別 T,而非 Nullable<T>。實務開發中常需進行 null 判定以避免異常:
object obj = new object();
string objName = string.Empty;
if (obj != null) { objName = obj.ToString(); }
三元運算子改進:string objName = obj == null ? string.Empty : obj.ToString();
.NET 3.0 引入 ?? 運算子,更優雅:
object obj = null;
string objName = (obj ?? string.Empty).ToString();
規則:若左運算元為 null,回傳右運算元值;否則回傳左運算元值。適用於可為 Null 型別與參考型別。
大師們(Bob 大叔、Martin Fowler)均討論過 Null Object Pattern。核心思想:為物件提供指定型別,取代物件為空的情況,提供「什麼也不做」的行為。
典型操作遍佈系統:
if (user != null) { manager.SendMessage(user); }
引入 NullUser 實作相同介面 IUser,方法皆為空實作,並提供 IsNull 屬性回傳 true。將 user == null 判斷轉為 user.IsNull,確保回傳有效物件而非無意義的 null,避免 NullReferenceException。
實作 INullable 介面(含 IsNull 屬性),UserManager 中以 value ?? new NullUser() 確保屬性永不為 null。測試證實強制設為 null 後呼叫方法仍穩定。
擴充方法(Extension Method)讓 IsNull 判斷更簡潔:
public static class UserExtension
{
public static bool IsNull(this User user) => null == user;
}
IList<User> 中無需 null 判斷)。IsNull 判斷(介面或擴充方法)。通過本文可基本掌握 null 話題的方方面面。技術魅力在於:即便是「什麼都沒有」的 null,依然有許多值得探索、思考與分享。LINQ 中的 null、SQL 中的 null,思考仍在繼續。