程序地带

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


为你的项目启用可空引用类型
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 种配置,配置如下


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 的时候就不能很好的工作,来看一个示例:


image-20210117223138360


从上面的示例来看,在使用 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/

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/weihanli/p/14290642.html

随机推荐

SQLServer如何设置允许远程连接

第一步:选中计算机名称右击,选择属性第二步:安全性选择页中,选择SQLServer和Windows身份验证模式后确定。第三步:登录...

Grits 阅读(233)

箭头函数写法_一文讲透ES6箭头函数

前言最近是校招季,有时会问同学关于箭头函数和普通函数异同,往往能够得到一些表面的回答,但不够全面不够深入。于是写一篇来彻底讲透箭头函数。箭头函数是ES6引入到...

爱浪的刀 阅读(637)

箭头函数写法_ES6 箭头函数的适用场景

箭头函数写法_ES6 箭头函数的适用场景

箭头函数(也称作“胖箭头函数”)无疑是ES6最流行的特性之一。他们引入了一种编写具体函数的新方式。ES5语法示例:functiontimesTwo(param...

宋昕冉 阅读(712)

基于java springboot 疫情打卡微信小程序源码

在互联网环境下结合校园疫情防控要求,开发了基于微信小程序的校园体温填报,信息预警管理平台.采用微信开发工具和基于java语言的springboot框架实现了平台客户端和后台管理端.前台客户端主要功能包...

weixin_47190906 阅读(994)

潜龙会钱智龙 时代先锋 敢为人先

给潜龙会钱智龙老师的一封感谢信您好!我只是一名普通的投资者,投资股票也有四年了,跟潜龙会的老师们相比,只算得上小学生的水平。之前因为不懂投资股票...

中华快讯 阅读(483)

数据库表结构设计方法及原则

在目前的企业信息系统中,数据库还是最佳的数据存储方式,虽然已经有很多的书籍在指导我们进行数据库设计,但应该那种方式是设计数据库的表结构的最好方法、设计时应遵从...

素小暖 阅读(786)