為你的專案啟用可空參考型別
Intro
C# 從 8.0 開始引入了可空參考型別,我們可以為專案啟用可空參考型別來借助編譯器來幫助我們更好的處理代碼中的空參考的處理,可以避免我們寫很多不必要 null 檢查,提高我們的效率
Why
為什么我們要啟用可空參考型別呢,首先我們可以看一下 asp.net core 專案,asp.net core 的專案正在大量的使用可空參考型別,詳情可以參考:
https://github.com/dotnet/aspnetcore/issues/5680
Updating ASP.NET Core to use C# 8's nullable reference types would:
- 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 的,對開發者更為友好
How
接著我們就來看一看如何為我們的專案啟用可空參考型別吧,微軟的檔案上提供了比較詳細的說明,詳細可以參考文末的參考鏈接
啟用可空參考型別只需要在專案檔案中添加 <Nullable>enable</Nullable> 即可,LangVersion 需要設定為 8 及以上,
Nullable 背景關系包含了兩個背景關系一個是 Nullable annotation context(支持 ? 表示可為空的參考型別),一個是 Nullable warning context(支持編譯器針對可空參考型別的警告)
Nullable 背景關系有 4 種配置,配置如下
enablewarningsannotationsdisable
| Setting | Warning Context Status | Annotation Context Status |
|---|---|---|
| enable | enabled | enabled |
| warning | enabled | disabled |
| annotations | disabled | enabled |
| disable | disabled | disabled |
推薦直接使用 enable 啟用可空參考型別,只啟用 annotation 背景關系,編譯器不會針對可空參考型別的檢查做出警告,意義就不太大了,只啟用 warning 背景關系,可以使用在不想在自己應用中啟用可空參考型別,可以嘗試這個配置,不配置 nullable 或者配置 disable 則可以完全禁用可空參考型別
除了針對 project 的 global 的配置之外,我們還可以在專案源代碼里通過 #nullable 來改變區域的可空背景關系配置,通過 #nullable restore 恢復默認的可空參考背景關系配置
#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 檢查)
Sample
首先可以看一個介面:
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 宣告變數的時候,會是一個可空的參考型別
More
使用可空參考型別可以一定程度上幫助我們減少不必要的 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 正在大力采用可空參考型別,大家還是可以了解一下的
Reference
- https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references
- https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/upgrade-to-nullable-references
- https://docs.microsoft.com/en-us/dotnet/csharp/nullable-migration-strategies
- https://github.com/dotnet/aspnetcore/issues/5680
- https://github.com/WeihanLi/WeihanLi.Npoi/pull/98
- https://github.com/WeihanLi/DbTool
- https://github.com/dotnet/samples/tree/master/csharp/NullableIntroduction/NullableIntroduction
- https://stackoverflow.com/questions/54526652/when-to-null-check-arguments-with-nullable-reference-types-enabled
- https://headspring.com/2020/06/02/applying-nullable-reference-types-in-fixie/
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/250004.html
標籤:C#
上一篇:怎么用Xml檔案作選單三級聯動?
下一篇:.NET探索平臺條件編譯
