乐趣区

关于c#:C80-可空引用类型

介绍

咱们的我的项目代码运行时最频繁的谬误之一就是 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 技术团队成员

退出移动版