在.NET 框架中使用 C# 8 和可空引用类型

本文要点:

  • 改变 C#版本需要直接修改项目文件
  • 全局启用可空引用类型只能在新的项目格式中实现
  • 可根据需要,在文件或行的基础上更改可空性
  • 使用可空属性以避免不必要的空检查。
  • 针对较旧的平台时,可使用 Nullable 包

尽管在.NET 框架中,C# 8 的一部分将永远不会得到支持,但是,如果我们知道一些技巧的话,那么可以启用可空引用类型

启用 C# 8

第一步是确保我们使用的是 Visual Studio 2019 16.3 版或更高版本。

然后,我们需要为 C# 8 配置我们的项目。如果我们习惯使用 Visual Studio 的话,那么,我们可能期望能够简单地更改项目设置。不幸的是,那种方式已经无效了。

在.NET 框架中使用 C# 8 和可空引用类型

在新规则下, C#的默认版本由我们要面向的框架决定。只有.NET Core 3.0 和.NET Standard 2.1 可以用 C# 8 ,其他的都从 C# 7.3 版本开始。

我们可以通过编辑项目文件来覆盖它。打开项目的.csproj 文件,并在 PropertyGroup 中添加下面这行代码:

复制代码
 
 
<LangVersion>8.0</LangVersion>

如果我们使用现代项目格式的话,那么,在解决方案资源管理器(Solution Explorer)中双击该项目就可以将其打开。我们可以识别出这个格式,因为 XML 文件看起来是这样的:

复制代码
 
 
<Project Sdk="Microsoft.NET.Sdk">

如果我们使用遗留项目格式的话,那么,直接编辑它有点复杂。可以选择关闭 Visual Studio,使用 Notepad 或其他文本编辑器。或者,我们可以安装 Visual Studio 的 Power Commands ,它会添加一个“Edit Project File”命令。作为参考,XML 文件的根看起来类似这个:

复制代码
 
 
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

启用可空引用类型:

接下来是启用可空引用类型功能。如果我们使用现代项目格式的话,那么,我们可以通过在语言版本的后面添加如下所示的代码行来全局化实现这一点:

复制代码
 
 
<Nullable>enable</Nullable>

如果我们使用遗留项目格式的话,那么,这样做就不起作用。我们不会得到错误提示,编译器只是忽略这个设置。因此,我们必须逐个文件地启用它。要做到这一点,必须在每个文件的顶部添加可空指令:

复制代码
 
 
#nullable enable

如果我们希望逐步启用该功能,那么,在现代项目中也可以这么做。

可空性属性

有各种各样的属性可用于微调空检查器的行为。为了解释该功能,可以考虑如下函数:

复制代码
 
 
bool TryGet(int key, out Customer? customer)

隐含的约定是,如果该函数返回 true,那么,customer 参数将不为空。反之,如果该函数返回 false,那么,customer 参数将为空。

但是,这不是签名的一部分,因此,如果我们要这样使用这个函数,那么,我们就总是需要在 customer 上进行一个无关的空检查。解决方法是,添加一个阐明行为的属性:

复制代码
 
 
bool TryGet(int key, [NotNullWhen(true)] out Customer? customer)

从编译器的角度来看,这意味着,如果返回 true,那么,customer 将永远不会是空值。如果返回的是 false,它没有说明会发生什么情况,但是,这仍然足以解决签名问题了。

在《尝试可空引用类型》这篇文章中,Phillip Carter 详细地描述了各种属性:

  • 条件化的后置条件:MaybeNotNullWhen(bool)、 NotNullWhen(bool)
  • 依赖是非为空:NotNullIfNotNull
  • 流:DoesNotReturn、DoesNotReturnIf(bool)
  • 后置条件:MaybeNull、NotNull
  • 前置条件:AllowNull、DisallowNull

旧项目中的可空性属性

为了实际使用这些属性,需要定义它们。如果我们在使用.NET Standard 2.1 或.NET Core 3.0 的话,那么,这些已经是现成的了。否则,我们将不得不创建它们,把它们作为我们项目的一部分。

处理这个问题的传统方式是创建一个新的.NET Core 3 项目,使用 F12 对所需的属性进行反向工程。然后,我们可以把它粘贴到我们的项目上,并添加缺少的细节,对于属性来说,这只需要几分钟时间。

一种更简单的方法是,简单地安装 Maunel Römer 的 Nullable 包。这将把 NullableAttributes.cs 文件复制到我们的项目中,其中包括所有必需的属性。这个包没有编译过的组件,只是一个源代码文件。

这两种方法都要确保所有的属性被标记成“内部”,而不是公共。这是为了避免与也可能向后移植属性的其他库发生冲突。

作者介绍

Johathan Allen 于 90 年代后期开始为一家医疗诊所开发 MIS 项目,逐步地将它们从 Access 和 Excel 提升到企业解决方案。在为金融行业编写了 5 年自动交易系统后,他成了多个项目的顾问,这些项目包括机器人仓库的 UI、癌症研究软件的中间层以及一家大型房地产保险公司的大数据需求。在业余时间,他热衷于对 16 世纪的武术进行研究及相关的写作。

相关推荐