C# 語言對空值NULL的處理提供了一整套機制和相應的語法糖,包優(yōu)雅而強大,個人感覺,大概也是所有編程語言中NULL處理機制最完善的。
空合操作符
string name = GetName() ?? “張三”;
空合操作符的運算規(guī)則是:若左側表達式求值后不為 null,則立即返回左側表達式值,右側表達式求值運算不再執(zhí)行;否則,對右側表達式求值并返回。因此,上述代碼實際上等價于:
string? temp = GetName(); string name = temp != null ? temp : “張三”;
空合運算符對于可空值類型(Nullable Value Types)同樣適用。
int? i1 = 1; var i2 = i1 ?? 100;
上面代碼中,可空值類型 i1 的值不為 null ,因此 i2 的值為 1。若 i1== null,則 i2 的值為100。因為最終運算結果不會包含 null 值,因此 i2 的類型被編譯器推斷為 int 而不是 int? 。代碼實際上等價于:
int? i1 = 1; var i2 = i1 != null ? i1.Value : 100;
空合操作符最神奇的地方是可以無限連接使用。
string str = str1 ?? str2 ?? str3 ?? “默認值”;
上面的代碼中,若 str1 不為 null ,則返回 str1 ,str2 和 str3 不再求值;否則繼續(xù)求 str2 值,若 str2 值不為 null,返回 str2 值,str3 不再求值。若 str2 值為 null,則繼續(xù)求 str3 值,若 str3 值不為 null,返回 str3 值,否則返回默認值。如果轉換成三元操作符,等價于:
string str = str1 != null ? str1 : (str2 != null ? str2 : (str3 != null ? str3 : “默認值”));
若轉換成 if 語句,則更加繁瑣:
if(str1 != null) { str = str1; } else if (str2 != null) { str = str2; } else if(str3 != null) { str = str3; } else str = “默認值”;
還有一個超級方便的空合賦值操作符。
name ??= “張三”;
即當 name 的值為 null 時,自動賦值右側表達式的值,等價于:
if (name == null) { name = “張三”; }
空條件運算符
空條件運算符的形式是 A?.B,即當 A == null 時,表達式值為 null。否則,就像正常的對象一樣調用屬性和方法。這樣做的好處是可以避免在 A 為 null 時拋出 NullReferenceException 異常。
object? obj = null; var result = obj?.ToString();
上述代碼實際上等價于:
object? obj = null; var result = obj == null ? null : obj.ToString();
因為結果可能為 null,因此 result 被編譯器推斷為 string? 而不是 string(開啟 nullable 特性的情況下)。
空條件運算符還可用在索引上。
string? str = “一段字符串”; var c = str?[1];
上述代碼中,若 str 為 null,則 c 的值為 null,否則按照正常索引取值,代碼等價于:
string? str = “一段字符串”; char? c = str == null ? null : str[1];
需要注意的是,在索引運算上運用空條件運算符,并不檢查索引的邊界,因此若索引值超出序列的范圍,會引發(fā) IndexOutOfRangeException。
string? str = “一段字符串”; var c = str?[6]; // 運行時引發(fā) IndexOutOfRangeException
空條件運算法同樣可以多個結合在一起使用。
A?.B?.C
等價于以下代碼:
A == null ? null : (A.B == null ? null : A.B.C)