当前位置: 首页 > news >正文

C# 8.0 如何在项目中开启可空引用类型的支持

C# 8.0 引入了可为空引用类型和不可为空引用类型。由于这是语法级别的支持,所以比传统的契约式编程具有更强的约束力。更容易帮助我们消灭 null 异常。

本文将介绍如何在项目中开启 C# 8.0 的可空引用类型的支持。


本文内容

    • 使用 Sdk 风格的项目文件
    • 在项目文件中开启可空引用类型的支持
      • 可为空注释(Annotation)上下文
      • 可为空警告上下文
    • 在源代码文件中开启可空引用类型的支持
    • 早期版本的属性
    • ReSharper 支持

使用 Sdk 风格的项目文件

如果你还在使用旧的项目文件,请先升级成 Sdk 风格的项目文件:将 WPF、UWP 以及其他各种类型的旧 csproj 迁移成 Sdk 风格的 csproj - 吕毅。

本文会示例一个项目文件。

由于现在 C# 8.0 还没有正式发布,所以如果要启用 C# 8.0 的语法支持,需要在项目文件中设置 LangVersion 属性为 8.0 而不能指定为 latest 等正式版本才能使用的值。

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.0</TargetFramework>
    <LangVersion>8.0</LangVersion>
  </PropertyGroup>

</Project>

在项目文件中开启可空引用类型的支持

在项目属性中添加一个属性 NullableContextOptions

    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>netcoreapp3.0</TargetFramework>
        <LangVersion>8.0</LangVersion>
++      <NullableContextOptions>enable</NullableContextOptions>
      </PropertyGroup>
    
    </Project>

此属性可被指定为以下五个值之一:

  • enable
    • 所有引用类型均被视为不可为空,启用所有 null 相关的(Nullability)警告。
  • disable
    • 无视所有引用类型是否为空,当设为此选项,则跟此前版本的 C# 行为一致。
  • safeonly
    • 所有引用类型均被视为不可为空,启用所有安全性的 null 相关警告。
  • warnings
    • 无视所有引用类型是否为空,但启用所有 null 相关的警告。
  • safeonlywarnings
    • 无视所有引用类型是否为空,但启用所有安全性的 null 相关警告。

这五个值其实是两个不同维度的设置排列组合之后的结果:

  • 可为空注释上下文
    • 用于告知编译器是否要识别一个类型的引用可为空或者不可为空。
  • 可为空警告上下文
    • 用于告知编译器是否要启用 null 相关的警告,以及警告的级别。

当仅仅启用警告上下文而不开启可为空注释上下文,那么编译器将仅仅识别局部变量中明显可以判定出对 null 解引用的代码,而不会对包括变量或者参数定义部分进行分析。

可为空注释(Annotation)上下文

当启动可为空注释上下文后,C# 编译器会将所有的类型引用变量识别为以下种类:

  • 不可为空
  • 可为空
  • 未知

于是,当你写出 string walterlv 的变量定义,那么 walterlv 就是不可为空的引用类型;当写出 string? walterlv 的变量定义,那么 walterlv 就是可为空的引用类型。

对于类型参数来说,可能不能确定是否是可空引用类型,那么将视为“未知”。

当关闭可为空注释上下文后,C# 编译器会将所有类型引用变量识别为以下种类:

  • 无视

于是,无论你使用什么方式顶一个一个引用类型的变量,C# 编译器都不会判定这到底是不是一个可为空还是不可为空的引用类型。

可为空警告上下文

例如以下代码:

string walterlv = null;
var value = walterlv.ToString();

在将 null 赋值给 walterlv 变量时,是不会引发程序异常的;而在后面调用了 ToString() 方法则会引发程序异常。

安全性区别就在这里。安全性警告仅会将编译期间可识别到可能运行时异常的代码进行警告(即下面的 walterlv.ToString()),而不会对没有异常的代码进行警告。如果是 enable,那么将 null 赋值给 walterlv 变量的那一句也会警告。

在源代码文件中开启可空引用类型的支持

除了在项目文件中全局开启可空引用类型的支持,也可以在 C# 源代码文件中覆盖全局的设定。

  • #nullable enable
  • #nullable disable
  • #nullable safeonly
  • #nullable restore

或者

  • #pragma warning disable nullable
  • #pragma warning enable nullable
  • #pragma warning restore nullable
  • #pragma warning safeonly nullable

早期版本的属性

在 Visual Studio 2019 Preview 2 升级之后才引入 NullableContextOptions 属性,而在此之前,用于控制可空引用类型开关的属性是 NullableReferenceTypes。现在,这个旧的属性已经废弃。

ReSharper 支持

ReSharper 从 2019.1.1 版本开始支持 C# 8.0,如果使用早期版本,就会到处报错。


参考资料

  • Nullable reference types - Microsoft Docs
  • c# - What is the difference between NullableContextOptions and NullableReferenceTypes? - Stack Overflow

我的博客会首发于 https://blog.walterlv.com/,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。

如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。

相关文章:

  • C# 8.0 可空引用类型中的各项警告/错误的含义和示例代码
  • C# 可空引用类型 NullableReferenceTypes 更强制的约束:将警告改为错误 WarningsAsErrors
  • ClearType 的原理:Windows 上文本的亚像素控制
  • 使用 7-Zip 的命令行版本来压缩和解压文件
  • 在项目文件 csproj 中或者 MSBuild 的 Target 中使用 % 引用集合中每一项的属性
  • MSBuild 中的特殊字符($ @ % 等):含义、用法以及转义
  • WPF 获取元素(Visual)相对于屏幕设备的缩放比例,可用于清晰显示图片
  • Visual Studio 通过修改项目的调试配置文件做到临时调试的时候不要编译(解决大项目编译缓慢问题)
  • 使用 dotnet 命令行配合 vscode 完成一个完整 .NET 解决方案的编写和调试
  • 如何修改 Visual Studio 新建项目时的默认路径
  • 使用 EnumWindows 找到满足你要求的窗口
  • WPF 程序鼠标在窗口之外的时候,控件拿到的鼠标位置在哪里?
  • Visual Studio 使用 Parallel Builds Monitor 插件迅速找出编译速度慢的瓶颈,优化编译速度
  • 通过分析 WPF 的渲染脏区优化渲染性能
  • 使用 System File Check (SFC) 工具检查并修复 Windows 系统文件
  • [译]如何构建服务器端web组件,为何要构建?
  • 【划重点】MySQL技术内幕:InnoDB存储引擎
  • 【跃迁之路】【735天】程序员高效学习方法论探索系列(实验阶段492-2019.2.25)...
  • 2018以太坊智能合约编程语言solidity的最佳IDEs
  • Angular 2 DI - IoC DI - 1
  • iOS仿今日头条、壁纸应用、筛选分类、三方微博、颜色填充等源码
  • JavaScript学习总结——原型
  • Java精华积累:初学者都应该搞懂的问题
  • jdbc就是这么简单
  • leetcode-27. Remove Element
  • nginx(二):进阶配置介绍--rewrite用法,压缩,https虚拟主机等
  • PyCharm搭建GO开发环境(GO语言学习第1课)
  • Quartz初级教程
  • SegmentFault 2015 Top Rank
  • Selenium实战教程系列(二)---元素定位
  • spark本地环境的搭建到运行第一个spark程序
  • ViewService——一种保证客户端与服务端同步的方法
  • 翻译--Thinking in React
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 观察者模式实现非直接耦合
  • 用Python写一份独特的元宵节祝福
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • ​2020 年大前端技术趋势解读
  • ​LeetCode解法汇总1410. HTML 实体解析器
  • ​Linux Ubuntu环境下使用docker构建spark运行环境(超级详细)
  • # Maven错误Error executing Maven
  • #define MODIFY_REG(REG, CLEARMASK, SETMASK)
  • #我与Java虚拟机的故事#连载15:完整阅读的第一本技术书籍
  • $forceUpdate()函数
  • ( 用例图)定义了系统的功能需求,它是从系统的外部看系统功能,并不描述系统内部对功能的具体实现
  • (ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY)讲解
  • (板子)A* astar算法,AcWing第k短路+八数码 带注释
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (九十四)函数和二维数组
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理第3章 信息系统治理(一)
  • (十八)SpringBoot之发送QQ邮件
  • (一)Neo4j下载安装以及初次使用
  • *** 2003
  • *2 echo、printf、mkdir命令的应用
  • .bat批处理(六):替换字符串中匹配的子串