歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> C#的未來:追蹤空引用

C#的未來:追蹤空引用

日期:2017/3/1 9:29:47   编辑:Linux編程

在 .NET 中最常見的錯誤類型大概要數空引用異常了。這個錯誤的根源在於 C# 無法表達出非空引用的概念,這也導致讓編譯器強制進行空檢查變成一種過於繁重的任務。

為了應對這個問題,某條提議建議使用一種強制引用,以及一種明確的可空引用的定義。在提議中,可空引用將使用?後綴進行定義,正如可空值類型的定義方式一樣。而強制引用,或者說非空引用將使用!後綴進行定義。

強制引用以及可空引用都應該被視為一種僅限於語言本身的概念,它們只是改變了編譯器的行為,但不會改動所生成的 IL 代碼。

在編譯器允許訪問可空引用對象的任何方法或屬性之前,必須明確地檢查空引用。並且在將某個可空引用轉型為強制引用之前,也必須對空引用進行檢查。

強制引用需要編譯器證實其中包含的值不可為空。由於這是一種僅限於編譯器的規則,因此無法保證在反序列化等場景中能夠同樣生效。

在閱讀這條提議的完整內容時,你會注意到其中提到的某個術語“一般引用”。它指的是 C# 中的普通引用,它既不是強制的,也不是明確定義為可空的。由於這種引用將被視為遺留代碼,因此可以通過 AllowGeneralReferences 這一屬性告訴編譯器不允許在代碼中使用一般引用。

在結合隱式變量定義時,可以在 var 關鍵字中使用!或?後綴。

類型轉換

根據這條提議,你可以隱式地將某個強制引用轉換為可空引用。不過,它不允許你將某個一般引用轉換為可空引用,對此有如下的解釋:

假設一下這個一般引用的意圖(或許它從概念上來說應當是強制的,而不是一種可空的概念)。

但這種說法是沒有什麼道理的,如果某個實際的強制引用能夠隱式地轉換為可空引用,那麼某個“概念性的強制引用”應該也可以實現這一轉換。

與之類似的是,從強制引用或可空引用轉換為一般引用也是不允許的,這也是基於同樣的理由,盡管該理由存在著一些疑問。

構造函數

對於非空引用類型的這一提議中還存在著一條有待解決的問題,那就是很難在構造函數中強制這種非空性。對此,有一條提議就是不要處理這一問題。就像我們在構造函數中可以多次為某個“只讀”字段進行賦值一樣,我們可以直接聲明這條規則在構造函數中並不生效,需要開發者本人注意到這一點。

這條提議乍一看起來會產生反效果,但它實際上是很有道理的。開發者們在構造函數中本來就需要注意訪問可能尚未初始化的字段會帶來的問題。這一條提議也沒有改變這一現象,如果開發者忽略了這一點,那麼構造函數就會產生錯誤,而這將減少出現空引用異常的風險。

混合新代碼與遺留代碼

非空引用這條提議還需要面對另一個問題,那就是如何處理遺留代碼。比方說,如果已經對基礎類庫進行升級,在其中使用了這個新的語法。而現有的應用程序可能無法立即進行代碼的改動,那麼必須要有某種機制能夠關閉這一新語法的使用。這條提議中提供了一個 IgnoreNewStyleReferences 屬性,可以通過它忽略某個外部程序集中所使用的新的引用語法。

關於可空引用的更多內容

在前文中,我們提到過可空引用可能會處於兩種狀態之一:未知或判定為非空(注:也可能判定為空)。這條提議對此進一步說明,如果某個引用已經判定為空,那麼在之後的代碼中就無法使用它(賦值給另一個可空變量),開發者必須使用一個硬編碼的空值,這也能夠讓代碼的意圖表現得更加清晰。

其它問題

這一提議還有許多需要處理的問題。比方說,是否能夠定義強制引用的數組?在使用反射時如何暴露強制引用與非空引用?它們與泛型之間又將如何交互?

英文原文:C# Futures: Nullability Tracking

Copyright © Linux教程網 All Rights Reserved