为你的项目启用可空引用类型

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:

  1. Help ASP.NET Core libraries avoid null reference exceptions internally. It will help us find and prevent our bugs and increase our developer productivity

  2. 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 种配置,配置如下

  • 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 则可以完全禁用可空引用类型

除了针对  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 的,但是编译器现在还没这么智能,还需要进一步的优化,Resharper 是可以检测出来的,对于测试项目你如果遇到这种情况可以禁用可空引用类型或者使用 annotations 配置,或者可以声明一个不可空的引用类型变量

最近改了两个项目,开始使用了可空引用类型,有需要可以参考一下,一个是类库项目,把原来使用 Jetbrains.Annotations 替换成了可空引用类型,可以参考:https://github.com/WeihanLi/WeihanLi.Npoi ,另一个是一个应用项目,可以参考:https://github.com/WeihanLi/DbTool/

最后想说,鉴于目前 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/

为你的项目启用可空引用类型相关推荐

  1. 如何将C# 7类库升级到C# 8?使用可空引用类型

    这篇文章将介绍将C# 7类库升级到C# 8(支持可空引用类型)的一个案例.本案例中使用的项目Tortuga Anchor由一组MVVM风格的基类.反射代码和各种实用程序函数组成.之所以选择这个项目,是 ...

  2. C#8.0可空引用类型的使用注意要点

    C#8.0可空引用类型的使用注意要点 最近VS2019正式版发布了,装下来顺便试用了一下C#8.0,最大的看点应该就是可空引用类型了.不过C#8.0仍然处于Beta的状态,而且试用时也遇到了几个坑. ...

  3. C#8.0可空引用类型的使用注意要点 1

    最近VS2019正式版发布了,装下来顺便试用了一下C#8.0,最大的看点应该就是可空引用类型了.不过C#8.0仍然处于Beta的状态,而且试用时也遇到了几个坑. 背景知识说明: 所谓的可空引用类型是指 ...

  4. .NET 6新特性试用 | 可空引用类型

    前言 在查看<隐式using指令>功能时,我们在csproj中发现这样一个属性: 那么,Nullable到底是干嘛的? 可为空上下文 严格来说,这不是新特性,而是C# 8.0引入的特性之一 ...

  5. C# 8 新特性 - 可空引用类型

    Nullable Reference Type. 在写C#代码的时候,你可能经常会遇到这个错误: 但如果想避免NullReferenceException的发生,确实需要做很多麻烦的工作. 可空引用类 ...

  6. 微软在C# 8中引入预览版可空引用类型

    微软已经为开发者提供了预览版的可空引用类型(Nullable Reference Type),想尝鲜的开发者可以尝试这个新特性,并提供反馈. \\ 预览版可空引用类型是Visual Studio 20 ...

  7. 关于是否在C#中加入不可空引用类型的争论

    来自微软的Mads Togersen在近期所提出的一条提议,即在C#语言中加入对不可空引用类型的支持在.NET社区中引起了热烈的争论.人们对此提议的反应大相径庭,既有人对此表示赞赏,也不乏倾向于保持现 ...

  8. C# 面向对象编程 (杂1)引用同解决方案下的其他项目,值类型和引用类型,字符串常用方法

    C# 面向对象编程 (杂1)引用同解决方案下的其他项目,值类型和引用类型,字符串常用方法 文章目录 C# 面向对象编程 (杂1)引用同解决方案下的其他项目,值类型和引用类型,字符串常用方法 1.命名空 ...

  9. Vue3+Ant-design项目启用ts/typescript

    Ant-design官方文档提供了js和ts两种案例,按照文档给项目install ant-design后写了个组件编译时发现只要加上`<script lang="ts"&g ...

最新文章

  1. 获取服务(getService)
  2. /usr/lib/ocf/resource.d/pacemaker/ping: line 296
  3. javascript调用activex控件
  4. [html] 如何禁止html页面缓存?
  5. 帆软报表重要Activator之DesignerStartup
  6. OC代码调用C++代码的回调函数步骤
  7. 面向对象和面向过程思想 oc
  8. COMSOL仿真分析视频教程
  9. 通信工程是计算机类还是电子信息类公考,通信工程属于电子信息类吗
  10. saas自媒体运营管理系统
  11. 数据库查数据 索引
  12. 焱融科技与趋动科技携手解决一站式存算难
  13. 复杂稀缺类分析:稀缺与不重要能否划等号?
  14. Java Web 网络商城案例演示一、(环境搭建)
  15. textarea标签中的换行符和空格
  16. 找到数组里消失的数字(鸽笼原理)
  17. vue 给取data值_vue获取data值的方式分析
  18. 第一讲 OSG编译 认识OSG
  19. Java项目:SSM水果蔬菜商城批发网站
  20. C语言刷题系列——12.判断回文字符串

热门文章

  1. LeetCode 最大正方形
  2. 第8章 java中的并发工具类
  3. css_oneday
  4. 辉光UIView的category
  5. Gruntjs: grunt-contrib-jst
  6. windows7黑屏修复_如何在Windows 10更新后修复黑屏
  7. 程序代码初学者_初学者:如何使用热键在Windows中启动任何程序
  8. gfi截图_GFI Backup Home Edition是Windows的免费数据备份实用程序
  9. JavaScript 使用random()生成随机数
  10. IE8采用IE7模式