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

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

Intro

C# 从 8.0 开始引入了可空引用类型,咱们能够为项目启用可空引用类型来借助编译器来帮助咱们更好的处理代码中的空引用的处理,能够避免咱们写不少没必要要 null 检查,提升咱们的效率git

Why

为何咱们要启用可空引用类型呢,首先咱们能够看一下 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

  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 的,对开发者更为友好app

How

接着咱们就来看一看如何为咱们的项目启用可空引用类型吧,微软的文档上提供了比较详细的说明,详细能够参考文末的引用连接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 检查)

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

相关文章
相关标签/搜索