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