C#將引入可空的引用型別
是的,標題沒錯。C#其中一份新提案假定,所有的引用型別在預設情況下都是不可空的。在新語法下,你需要顯式地標明一個引用變數是可空的,就像對值型別所做的那樣。
\\和值型別一樣,T是指不可空型別,而T?是指可空型別。以下情況會產生警告:
\\- 取消對可空變數的引用;\\t
- 一個可空變數或引數被賦值給一個不可空變數;\\t
- 從T?[]轉換到T[];\\t
- 從T[]轉換到T?[];\\t
- 將一個空字面量賦值給一個不可空變數或引數;\\t
- 建構函式沒有給所有的不可空欄位賦值;\
對於前兩種情況,如果你使用了感嘆號運算子(x!)或者編譯器能夠證明已經執行了null檢查,那麼警告將被忽略。
\\實現細節
\\底層編譯器將會忽略可空註解,因此,那不是問題。不過,在程式集級,應該有某種標記,可以說明庫在編譯時啟用了可空註解。
\\由於所有這類可空的東西從技術上講都是一種破壞性修改,所以當前的計劃是允許開發人員選擇下面的類別:
\\- 可空警告;\\t
- 不可空警告;\\t
- 警告來自其他檔案中的註解。\
提案繼續寫道:
\\\\\選擇參與的粒度表明,這是一個類似分析器的模型,大段的程式碼通過編譯指令選擇參與和退出,使用者可以選擇安全級別。此外,每個庫的選項(“在準備好應對後果之前,忽略JSON.NET中的註解”)可以表示為程式碼中的屬性。
\
根據預期,這種設計要達到以下三個目的:
\\- 使用者可以像他們希望的那樣逐步採用可空屬性檢查;\\t
- 庫作者可以新增可空屬性註解,而不必擔心破壞使用者的程式碼;\\t
- 除此之外,沒有“配置噩夢”之感。\
對於同一個方法,你不必進行可空和不可空的過載。雖然從技術上講,CLR支援這樣做,但那不是CLS或者通用語言規範的組成部分。這意味著,大多數編譯器都會不知道發生了什麼。HaloFour作了如下說明:
\\\\\\
modreq
不是CLS。modopt
確實支援過載,但需要具體瞭解所有重要編譯器的這個部分,因為至少要將修飾符複製到呼叫簽名裡。兩者都會破壞與現有方法簽名的相容。對於希望在整個BCL快速傳播的東西來說,使用modopt
會成為巨大的障礙。
泛型
\\在使用泛型時,以下情況會出現額外的警告:
\\- 從C\u0026lt;T\u0026gt;轉換到C\u0026lt;T?\u0026gt;,除非型別引數是協變數(出);\\t
- 從C\u0026lt;T?\u0026gt;轉換到C\u0026lt;T\u0026gt;,除非型別引數是反變數(入);\\t
- 使用C\u0026lt;T?\u0026gt;,然後將型別引數限制為不可為空。\
使用“class”,則泛型強制非空。使用“class?”則允許空值。該提案繼續寫道:
\\\\\如果一個型別引數沒有約束,或者只有可空約束,則情況會稍微複雜一些:這意味著,相應的型別引數既可以為空,也可以不為空。在那種情況下,安全的做法是將型別引數既作為可空引數來處理,又作為不可空引數來處理,任何一個不滿足,就發出警告。
\
陣列
\\陣列是一項特殊的挑戰,因為在一個不可為空的陣列中,不一定可以確保每個槽都有一個值。
\\\\\對於一個非空引用陣列,我們無法通過充分地跟蹤來保證陣列的所有元素都被初始化。不過,在從陣列讀取資料或者傳遞陣列之前,如果新建立的陣列沒有元素被賦值,我們就會發出警告。那應該可以處理常見的情況,而又不帶來太多干擾。
\
開放性設計問題
\\使用default(T)應該發出警告嗎?還是說假定它會返回T?,而不是T?
\\可以刪除區域性變數上的?而根據使用情況推斷其可空性嗎?
\\引數可以使用T! x模式自動生成null檢查嗎?
\\可以調整一下可空值型別,以便讓開發人員可以使用x.method代替x.Value.method嗎(這用在當x已知非空時,比如已經成功完成了null檢查)?
\\更多資訊
\\相關文章
- 如何將C# 7類庫升級到C# 8?使用可空引用型別C#型別
- C#8.0 可空引用型別C#型別
- 為你的專案啟用可空引用型別型別
- c#:值型別&引用型別C#型別
- C#的型別——值型別與引用型別C#型別
- 瞭解下C# 可空型別(Nullable)C#型別Null
- C#可空型別,int可以為nullC#型別Null
- 快速瞭解C# 8.0中“可空引用型別(Nullable reference type)”語言特性C#型別Null
- 【C#之值型別vs引用型別】C#型別
- C# 物件比較(值型別、引用型別)C#物件型別
- C#變數型別(1):引用型別和值型別 (轉)變數型別
- C# 泛型 引用型別約束 值型別約束C#泛型型別
- 原來C#的可空型別可以直接參與計算C#型別
- 圖解C#的值型別,引用型別,棧,堆,ref,out圖解C#型別
- C#引用型別和值型別在堆、棧中的儲存C#型別
- C#學習筆記之值型別與引用型別C#筆記型別
- C#程式設計引用型別和值型別 以及引用傳遞和值傳遞C#程式設計型別
- C#名稱空間、型別的別名管理C#型別
- 引用型別型別
- Go 的引用型別Go型別
- 值型別與引用型別的區別型別
- Java的基本型別和引用型別Java型別
- 值型別和引用型別型別
- JavaScript引用型別-Object型別JavaScript型別Object
- 值型別與引用型別型別
- js引用型別JS型別
- javascript:引用型別JavaScript型別
- JavaScript的原生引用型別JavaScript型別
- JavaScript值型別和引用型別JavaScript型別
- ECMAScript 原始型別與引用型別型別
- Swift值型別和引用型別Swift型別
- js基本型別和引用型別區別JS型別
- JAVA 基本型別與 引用型別區別Java型別
- javascript基本型別 引用型別 基本包裝型別JavaScript型別
- JavaScript - 基本型別與引用型別值JavaScript型別
- Kotlin——初級篇(六): 可空型別、空安全、非空斷言、型別轉換等特性總結Kotlin型別
- 引用型別的深拷貝型別
- Golang 引用型別-mapGolang型別