介绍

咱们的我的项目代码运行时最频繁的谬误之一就是 System.NullReferenceException 异样,c#8.0减少的可为空援用类型就是用来帮忙开发者升高甚至打消NULL异样。咱们须要留神的是可空援用类型是语法级别的性能,也就是代码编写的时候就会受到编程束缚,这个与可为空值类型是不一样的。我的项目反对c#8.0请参见C# 语言版本控制。

目录

  • 在我的项目中启用可空援用类型反对
  • 将变量标注为可空援用类型
  • 应用示例
  • 进阶
  • 缺点

在我的项目中启用可空援用类型反对

<Project Sdk="Microsoft.NET.Sdk.Web">  <PropertyGroup>    <TargetFramework>net6.0</TargetFramework>    <Nullable>enable</Nullable>  </PropertyGroup>    </Project>

在我的项目文件中减少<Nullable>enable</Nullable>后,我的项目代码中的援用类型将被解析拆分为不可空援用类型可空援用类型

将正告晋升为异样

可空援用类型性能是以正告的模式呈现,并不会烦扰我的项目生成编译,约束力较弱。如果想严格要求本身,那咱们可将特定的正告变为异样来晋升约束力。

<Project Sdk="Microsoft.NET.Sdk.Web">  <PropertyGroup>    <TargetFramework>net6.0</TargetFramework>    <Nullable>enable</Nullable>                                  <WarningsAsErrors>        $(WarningsAsErrors);CS8600;CS8601;CS8602;CS8603;CS8604;CS8609;CS8610;CS8614;CS8616;CS8618;CS8619;CS8622;CS8625    </WarningsAsErrors>  </PropertyGroup>    </Project>

相干技术文档C# 编译器选项 - 谬误和正告 | Microsoft Docs,Non-nullable references with C# 8 and .NET Core 3.0 · Cezary Piątek Blog (cezarypiatek.github.io),大家在编写代码时遇到Microsoft.CodeAnalysis.CSharp分析器所给的正告代码,都可依照本人的要求将其变为异样来束缚本人。

将变量标注为可空援用类型

咱们平时应用的援用类型属于不可空援用类型,在其后附加?便为可空援用类型

string name; //不可空字符串string? adress; //可空字符串

泛型

public TKey GetKey<TKey>(){    //必须返回不可空类型}public TValue? GetValue<TValue>(){    //可返回可空类型}

应用示例

如上示例,因为Student领有默认的空构造函数new Student(),此构造函数会使NameAdress属性为null,所以分析器收回了CS8618的正告。

咱们将空构造函数写上,此时正告智能的转移到构造函数上了。

咱们在构造函数中将可能为null的string类型属性附上值,正告打消。而string?类型无需解决,因为它是容许为null的。

以上两种形式也能够打消正告。

GetStudentNames办法中,咱们应用StudentEnglishName属性时,分析器收回了CS8604正告,因为EnglishName属性是可空援用类型,无奈放入List<string>中,只能放入在List<string?>中。

咱们应用??判断当EnglishName为null时,应用不可空援用类型属性Name,此时CS8604正告打消。

进阶

可空援用类型模式中,属性是能够被拆分为两种模式的,其一是属性是否可被赋值null,其二是属性的值是否可能为null。大家可能对这句话了解起来有点懵,请接着看上面的解说。

[AllowNull]

不可为null的援用类型属性容许被赋值null

下面代码中,Adress属性即便被赋值null,也不会使其值为null,不会在代码中引发潜在的Null异样。所以此场景是正当且被容许的。

[DisallowNull]

可为null的援用类型属性不容许赋值为null

Adress属性尽管默认值是null,但对其赋值null是不合理的。尽管不能赋值null,但获取Adress属性的值时仍可能为null,大家可在适合的场景应用[DisallowNull]

[NotNull]

可为null的援用类型属性的值永远不会是null,可放心使用

咱们应用GetStudentAdress办法返回StudentAdress属性,分析器并没有收回正告,因为分析器通过[NotNull]个性也晓得了Adress属性的值永远不会为null。

咱们尝试将Adress属性改为可能返回null值,分析器立马收回了CS8603正告,很给力。

[NotNullIfNotNull]

这个个性作用于办法中,用于通知其余程序员只有你不给我的办法传null参,我就不会返回null给你,你看着办。

[return: NotNullIfNotNull("student")]public string? GetStudentAdress(Student? student){    return student?.Adress;}

adressadress2有着不同的待遇。

缺点

有些场景分析器无奈剖析出潜在的null异样

Struct

public struct Student{    public string FirstName;    public string? MiddleName;    public string LastName;}public static class Program{    public static void PrintStudent(Student student)    {        Console.WriteLine($"First name: {student.FirstName.ToUpper()}");        Console.WriteLine($"Middle name: {student.MiddleName?.ToUpper()}");        Console.WriteLine($"Last name: {student.LastName.ToUpper()}");    }    public static void Main() => PrintStudent(default(FirstName));    public static void Main2() => PrintStudent(new Student());}

default(FirstName)new Student()中的FirstNameLastName 运行时为 null,编辑器此时未呈现任何正告。

public struct Foo<T>{    public T Bar { get; set; }}public static class Program{    public static void Main()    {        string s = default(Foo<string>).Bar;        string s2 = new Foo<string>().Bar;    }}

属性 Bar 在运行时为 null,而ss2是不可为null字符串类型,编辑器此时未呈现任何正告。

数组

数组也是可为 null 的援用类型中的已知缺点

using System;public static class Program{    public static void Main()    {        string[] values = new string[10];        string s = values[0];        Console.WriteLine(s.ToUpper());    }}

代码中的数组申明其元素为不可为null的string,而其元素在初始化时都为null,编辑器此时未呈现任何正告。

总结

将援用类型拆分为可空援用类型和不可空援用类型能够为咱们的我的项目代码带来质的晋升,团队之间合作或者应用第三方的类库都能够通过?标识来晓得办法的某个参数传null不会引发异样、属性赋值null不会引发异样,反之咱们应用某些属性或者办法的返参也能够晓得其是否可能为null,对于不可能为null的变量咱们就无需再麻烦的检测null值了,而在以前,咱们可能须要对每个变量都须要做null判断。感兴趣的同学连忙给本人的我的项目退出这个性能吧。

咱们正在口头,新的框架、新的生态

咱们的指标是自在的易用的可塑性强的功能丰富的强壮的

所以咱们借鉴Building blocks的设计理念,正在做一个新的框架MASA Framework,它有哪些特点呢?

  • 原生反对Dapr,且容许将Dapr替换成传统通信形式
  • 架构不限,单体利用、SOA、微服务都反对
  • 反对.Net原生框架,升高学习累赘,除特定畛域必须引入的概念,保持不造新轮子
  • 丰盛的生态反对,除了框架以外还有组件库、权限核心、配置核心、故障排查核心、报警核心等一系列产品
  • 外围代码库的单元测试覆盖率90%+
  • 开源、收费、社区驱动
  • 还有什么?咱们在等你,一起来探讨
通过几个月的生产我的项目实际,已实现POC,目前正在把之前的积攒重构到新的开源我的项目中

目前源码已开始同步到Github(文档站点在布局中,会缓缓欠缺起来):

MASA.BuildingBlocks

MASA.Contrib

MASA.Utils

MASA.EShop

BlazorComponent

MASA.Blazor

QQ群:7424099

微信群:加技术经营微信(MasaStackTechOps),备注来意,邀请进群

作者简介

吴炜来:MASA技术团队成员