空值合併賦值運算符
注意
本文是功能規格。 規格可作為功能的設計檔。 其中包含建議的規格變更,以及功能設計和開發期間所需的資訊。 這些文章會發佈,直到提議的規格變更完成並併併入目前的ECMA規格為止。
功能規格與已完成實作之間可能有一些差異。 這些差異是在的相關
冠軍問題:https://github.com/dotnet/csharplang/issues/34
總結
簡化常見的程式代碼撰寫模式,其中變數若為 Null,則會指派值。
在此提案中,我們將放寬 ??
的類型要求,以允許在左側使用具有不受限制類型參數的表達式。
動機
通常可以看到類似這樣的程式碼
if (variable == null)
{
variable = expression;
}
此提案會將不可多載的二進位運算元新增至執行此函式的語言。
至少有八個不同的社群提出了對此功能的要求。
詳細設計
我們會新增指派運算元的新形式
assignment_operator
: '??='
;
它遵循複合賦值運算符的現有語意規則(§12.21.4),不同之處在於,如果左側非空值,則會省略賦值。 此功能的規則如下。
給定的 a ??= b
,其中 A
是 a
的類型,B
是 b
的類型,如果 A0
為可為空的值類型,A
是 A
的基礎類型:
- 如果
A
不存在或是不可為 Null 的實值類型,就會發生編譯時期錯誤。 - 如果
B
無法隱含轉換成A
或A0
(如果A0
存在),則會發生編譯時期錯誤。 - 如果
A0
存在且B
能隱含轉換成A0
,且B
不是動態的,則a ??= b
的類型是A0
。a ??= b
會在運行時被評估為:
唯一不同的是var tmp = a.GetValueOrDefault(); if (!a.HasValue) { tmp = b; a = tmp; } tmp
a
只會被評估一次。 - 否則,
a ??= b
的類型會是A
。a ??= b
會在執行時評估為a ?? (a = b)
,但a
只會評估一次。
為了放寬 ??
的類型需求,我們會更新目前所述指定 a ?? b
的規格,其中 A
是 a
的類型:
- 如果 A 存在且不是可空類型或是引用類型,就會發生編譯時錯誤。
我們放寬這項要求至:
- 如果 A 存在且為不可為 Null 的實值型別,就會發生編譯時錯誤。
這可讓 Null 聯合運算符處理不受限制的類型參數,因為未限制的類型參數 T
存在,不是可為 Null 的類型,而且不是參考型別。
缺點
如同任何語言功能,我們必須質疑語言的額外複雜度是否在 C# 程序主體所提供的額外明確性中得到償還,而 C# 程式會受益於此功能。
替代方案
程序設計人員可以手動撰寫 (x = x ?? y)
、if (x == null) x = y;
或 x ?? (x = y)
。
未解決的問題
- [ ] 我們也應該支援
&&=
和||=
運算符嗎?
設計會議
沒有。