C# 從 8.0 開始引入了可空引用類型,咱們能夠爲項目啓用可空引用類型來藉助編譯器來幫助咱們更好的處理代碼中的空引用的處理,能夠避免咱們寫不少沒必要要 null 檢查,提升咱們的效率git
爲何咱們要啓用可空引用類型呢,首先咱們能夠看一下 asp.net core 項目,asp.net core 的項目正在大量的使用可空引用類型,詳情能夠參考:
https://github.com/dotnet/aspnetcore/issues/5680github
Updating ASP.NET Core to use C# 8's nullable reference types would:spring
- Help ASP.NET Core libraries avoid null reference exceptions internally. It will help us find and prevent our bugs and increase our developer productivity
- Provide guidance to developers who are using ASP.NET Core about which APIs can accept and return a null reference and which APIs can't. This would improve the developer experience of using ASP.NET Core
主要分爲兩方面,一方面是內部的代碼,對於內部代碼而言,使用可空引用類型咱們能夠藉助編譯器清晰地瞭解一個變量是否會爲 null
,不會爲 null
的變量就再也不須要進行空檢查了,另外一方面是對於使用的代碼,對於使用啓用空引用類型的類庫,編譯器能夠提供更好的空檢查支持,開發者能夠清晰地瞭解哪些 API 是容許爲 null
,哪些 API 是不容許爲 null
的,對開發者更爲友好app
接着咱們就來看一看如何爲咱們的項目啓用可空引用類型吧,微軟的文檔上提供了比較詳細的說明,詳細能夠參考文末的引用連接asp.net
啓用可空引用類型只須要在項目文件中添加 <Nullable>enable</Nullable>
便可,LangVersion
須要設置爲 8
及以上。ide
Nullable
上下文包含了兩個上下文一個是 Nullable annotation context
(支持 ?
表示可爲空的引用類型),一個是 Nullable warning context
(支持編譯器針對可空引用類型的警告)測試
Nullable
上下文有 4 種配置,配置以下優化
enable
warnings
annotations
disable
Setting | Warning Context Status | Annotation Context Status |
---|---|---|
enable | enabled | enabled |
warning | enabled | disabled |
annotations | disabled | enabled |
disable | disabled | disabled |
推薦直接使用 enable
啓用可空引用類型,只啓用 annotation
上下文,編譯器不會針對可空引用類型的檢查作出警告,意義就不太大了,只啓用 warning
上下文,可使用在不想在本身應用中啓用可空引用類型,能夠嘗試這個配置,不配置 nullable
或者配置 disable
則能夠徹底禁用可空引用類型ui
除了針對 project 的 global 的配置以外,咱們還能夠在項目源代碼裏經過 #nullable
來改變局部的可空上下文配置,經過 #nullable restore
恢復默認的可空引用上下文配置this
#nullable enable
: 設置 nullable annotation context 和 nullable warning context 爲 enabled.#nullable disable
: 設置 nullable annotation context 和 nullable warning context 爲 disabled.#nullable restore
: 恢復 nullable annotation context 和 nullable warning context 爲項目默認的配置.#nullable disable warnings
: 設置 nullable warning context 爲 disabled.#nullable enable warnings
: 設置 nullable warning context 爲 enabled.#nullable restore warnings
: 恢復 nullable warning context 爲項目配置#nullable disable annotations
: 設置 nullable annotation context 爲 disabled.#nullable enable annotations
: 設置 nullable annotation context 爲 enabled.#nullable restore annotations
: 恢復 annotation warning context 爲項目配置啓用可空引用類型以後,引用類型就不容許被設置爲 null
,若是要設置爲 null
,能夠在類型後加一個 ?
設置爲可空的引用類型如 string?
,或者使用 !
讓編譯器容許賦值,如:string a = null!;
(這也是咱們須要注意的一個地方,可空引用類型只是編譯器的檢查,並不可以嚴格的保證不會被賦值爲 null
,對於類庫項目,若是public
的 API 指望的參數是不可空的引用類型,除了使用不可空引用類型外,仍是須要保留 null
檢查)
首先能夠看一個接口:
public interface IPropertyConfiguration<out TEntity, TProperty> { IPropertyConfiguration<TEntity, TProperty> HasColumnTitle(string title); IPropertyConfiguration<TEntity, TProperty> HasColumnFormatter(string? formatter); IPropertyConfiguration<TEntity, TProperty> HasColumnInputFormatter(Func<string?, TProperty?>? formatterFunc); }
來看實現:
internal sealed class PropertyConfiguration<TEntity, TProperty> : PropertyConfiguration, IPropertyConfiguration<TEntity, TProperty> { private readonly PropertyInfo _propertyInfo; public PropertyConfiguration(PropertyInfo propertyInfo) { _propertyInfo = propertyInfo; PropertyName = propertyInfo.Name; ColumnTitle = propertyInfo.Name; } public IPropertyConfiguration<TEntity, TProperty> HasColumnTitle(string title) { ColumnTitle = title ?? throw new ArgumentNullException(nameof(title)); return this; } public IPropertyConfiguration<TEntity, TProperty> HasColumnFormatter(string? formatter) { ColumnFormatter = formatter; return this; } public IPropertyConfiguration<TEntity, TProperty> HasInputFormatter( Func<TEntity?, TProperty?, TProperty?>? formatterFunc) { InternalCache.InputFormatterFuncCache.AddOrUpdate(_propertyInfo, formatterFunc); return this; } }
能夠看到 HasColumnTitle
的參數中的 title
是不可空的引用類型,即便如此實現代碼裏仍是作了 null
檢查,並且可空引用類型在 throw new ArgumentNullException()
的時候也不會引起警告
警告示例:
若是賦值 null
給一個不可爲空的引用類型時,編譯器就會給出一個警告,示例以下:
在往一個不可空引用類型列表裏中添加 null
時,編譯器也會給出一個警告:
若是一個可空的的引用類型變量沒有檢查 null
的時候,也會有警告:
從上圖中能夠看出,使用 var
聲明變量的時候,會是一個可空的引用類型
使用可空引用類型能夠必定程度上幫助咱們減小沒必要要的 null 檢查,可是對於類庫項目來講,該有的 null 檢查仍是要有的
對於應用來講,藉助可空引用類型也能夠比較清晰地瞭解,哪些地方須要檢查 null,哪些地方不須要,能夠提高代碼質量
對於 null
包容運算符 !
,能夠將一個可能 null
的對象賦值給不可空的引用類型變量,儘可能不用使用,用了這個就是本身在代碼裏埋雷,原本不會爲 null
的變量、屬性也會出現 null
的狀況,若是尚未必要的 null
檢查,徹底是本身給本身挖坑。
可是在使用過程當中,感受有些狀況下仍是不夠智能,在測試項目中 Assert
的時候就不能很好的工做,來看一個示例:
從上面的示例來看,在使用 importedList[i].Id/Title
以前已經使用了 Assert.NotNull(importedList[i])
,理論上來講 importedList[i]
是不會爲 null
的,可是編譯器如今還沒這麼智能,還須要進一步的優化,針對這樣的狀況,能夠單獨聲明一個變量,使用 !
來聲明一個不可空的引用類型,想要禁用測試項目中的警告的話也能夠設置 nullable
級別爲 annotations
或者 disabled
最後想說,鑑於目前 asp.net core 正在大力採用可空引用類型,你們仍是能夠了解一下的