快速了解C# 8.0中“可空引用类型(Nullable reference type)”语言特性
Visual C# 8.0中引入了可空引用类型(Nullable reference type),通过编译器提供的强大功能,帮助开发人员尽可能地规避由空引用带来的代码问题。这里我大致介绍一下可空引用类型的基本内容。
刚开始接触这个语言特性的时候,可能会不太容易理解。引用类型本来不就是可以为空(null)的么,为啥还要特别地引入“可空引用类型”的概念呢?其实这是从编译器的角度要求开发人员在编程的时候就考虑某个变量是否有可能为空,从而尽可能地减少由空引用所带来的代码错误。
假设有如下类:
class Student
{
public Student(string name, DateTime dayOfBirth)
=> (Name, DayOfBirth) = (name, dayOfBirth);
public string Name { get; set; }
public DateTime DayOfBirth { get; set; }
public string Notes { get; set; }
}
此类定义了一个“学生”实体的基本信息,为了简化起见,这里只列出了需要讨论的几个属性:
- Name:学生姓名
- DayOfBirth:学生生日
- Notes:对学生信息的一些备注
假设我们有两个操作:在所有学生中,找出所有具有备注信息的学生,以及对所有学生按姓名排序,在C#中很容易使用Linq来实现:
var studentsHasNotes = students.Where(s => s.Notes.Length > 0);
以及:
var orderedStudents = students.OrderBy(s => s.Name);
到目前为止没啥问题,程序能够正常运行。然而仔细进行代码审查不难发现,在获取所有具有备注信息的学生的代码中(也就是上面第一段代码中),有可能出现空引用的异常,因为对于一个“学生”实体来说,它的Notes属性是有可能为null的。
现在我们打开“可空引用类型”这一语言特性,打开方式主要有两种:可以在项目级别,编辑csproj项目文件进行设置,也可以通过#nullable预编译指令来实现:
- 编辑csproj项目文件,加入
<Nullable>enable</Nullable>即可:

- 通过#nullable预编译指令来实现,只需要在代码中需要的地方加入#nullable指令即可:

启用“可空引用类型”这一语言特性之后你会发现,在上面的Student类的构造函数处出现了一个警告,提示在构造函数执行完成时,不可为空的“Notes”属性需要有一个不为空的值,建议将其设置为可空的string类型。为什么编译器仅提示Notes有可能为空,而不是Name属性呢?因为构造函数中已经为Name赋值了,因此,对于任何一个Student的对象,Name不可能为空,而Notes则不然。

Name不可能为空?它不是string类型么?万一在代码中它为空了怎么办?别急,编译器是不会允许出现这种情况的:

在此,我们将Notes属性设置为string?类型,于是你会发现,位于构造函数上的警告信息已经没有了,因为我们允许Student对象可以没有Notes数据,但在“找出所有具有备注信息的学生”这一操作时,又会出现警告,提示说Notes有可能为空:

于是,你会发现,在启用了可空引用类型的语言特性后,我们就需要仔细考察Student类型中的每一个引用类型的属性,看它在实际应用中是否有可能为空,如果可能为空,则用可空引用类型来定义属性,之后编译器就会帮助你来分析哪些地方有可能存在空引用。
在上面的“找出所有具有备注信息的学生”例子中,如果你觉得Notes肯定不会为空,那么也可以使用“!”操作符来覆盖编译器的警告信息,比如:

现在流行的.NET开源框架基本上都已经支持了可空引用类型了,而且如果你是一名开源框架的开发人员,也强烈建议在你的框架中启用这一语言特性来尽可能地避免空引用问题。比如,如果你在代码中启用了可空引用类型特性,那么当你从Newtonsoft.Json的JsonConverter类继承时,你会发现,你必须使用可空引用类型的函数重载:

但如果你没有启用可空引用类型特性,那么当你从Newtonsoft.Json的JsonConverter类继承时,你会发现,重载函数的签名与以前一样:

好了,对于C# 8.0的“可空引用类型”大致就介绍这么多,相信应该已经基本上概括了它的要点和使用方式,在日常开发中应该够用了。
快速了解C# 8.0中“可空引用类型(Nullable reference type)”语言特性的更多相关文章
- [译]C#8.0中一个使接口更加灵活的新特性-默认接口实现
9月份的时候,微软宣布正式发布C#8.0,作为.NET Core 3.0发行版的一部分.C#8.0的新特性之一就是默认接口实现.在本文中,我们将一起来聊聊默认接口实现. 众所周知,对现有应用程序的接口 ...
- C#中的值类型(value type)与引用类型(reference type)的区别
ylbtech- .NET-Basic:C#中的值类型与引用类型的区别 C#中的值类型(value type)与引用类型(reference type)的区别 1.A,相关概念返回顶部 C#中 ...
- 【Unity3D】中的空引用 Null Reference Exception
Null Reference Exception : Object reference not set to an instance of an object. 异常:空引用,对象的引用未设置到对象的 ...
- Nullable Reference Types 可空引用类型
在写C#代码的时候,你可能经常会遇到这个错误: 但如果想避免NullReferenceException的发生,确实需要做很多麻烦的工作. 可空引用类型 Null Reference Type 所以, ...
- C# 8 - Nullable Reference Types 可空引用类型
在写C#代码的时候,你可能经常会遇到这个错误: 但如果想避免NullReferenceException的发生,确实需要做很多麻烦的工作. 可空引用类型 Null Reference Type 所以, ...
- 迫不及待地体验了一把 C#8.0 中的可空引用类型(Nullable Reference)
在我之前的一篇博客 NullReferenceException,就不应该存在! 中,我吐槽了 C# 中 null 的弊端以及避免 null 的方法:事实上这本都是现代高级语言中极力推崇的做法.Kot ...
- C#8.0可空引用类型的使用注意要点
最近VS2019正式版发布了,装下来顺便试用了一下C#8.0,最大的看点应该就是可空引用类型了.不过C#8.0仍然处于Beta的状态,而且试用时也遇到了几个坑. 背景知识说明: 所谓的可空引用类型是指 ...
- C#3.0中的扩展方法
在实际应用中,开发者完成代码的编译后,除非重新编译更改后的代码,否则开发者很难在原有代码中添加新的功能. 在C#3.0中,提供了一个扩展方法的新特性,可以使得开发者在编译后的程序集里边添加相关的方法, ...
- vue2.0中使用less
第一部分:Less语言 与上一篇<vue2.0中使用sass>介绍的Sass语言一样,Less语言也是一种CSS的扩展语言,增加了变量.混合(minin).函数等功能,让CSS更易维护.方 ...
随机推荐
- POJ 3415 Common Substrings(后缀数组 + 单调栈)题解
题意: 给两个串\(A.B\),问你长度\(>=k\)的有几对公共子串 思路: 先想一个朴素算法: 把\(B\)接在\(A\)后面,然后去跑后缀数组,得到\(height\)数组,那么直接\(r ...
- xss之htmlspecialchars
源代码: 可以看到是用htmlspecialchars 对get参数message进行处理,但是他默认不对单引号进行处理的. 只对预定义的字符进行处理: & (和号)成为 & &quo ...
- MarkDown语法详解
MarkDown语法详解 编辑器:Typora 下载官网:https://typora.io 提速镜像:https://gitee.com/typora-mirror/Typora-Mirror/re ...
- 对于maven中无法加载类路径下的配置文件
<build> <resources> <resource> <directory>src/main/java</directory> &l ...
- VirtualBox All in One
VirtualBox All in One 虚拟机 / VM / Virtual Machine x86 and AMD64/Intel64 VirtualBox is a powerful x86 ...
- vs code & macOS services
vs code & macOS services Mac OS X, Open Folder With VS Code (right click) https://github.com/Mic ...
- 「NGK每日快讯」2021.1.7日NGK第65期官方快讯!
- Java线程池状态和状态切换
摘要 介绍线程池的五种状态RUNNING.SHUTDOWN.STOP.TIDYING和TERMINATED,并简述五种状态之间的切换. 在类ThreadPoolExecutor中定义了一个成员变量 ...
- python中yaml模块的使用
1.yaml库的导入 经过尝试,发现在python2 和python3语言环境下,安装yaml库的命令行语句不一样. python2: pip install yaml python3:pip ins ...
- redis的两种持久化的机制,你真的了解么?
redis提供了两种持久化的机制 RDB和AOF机制 RDB(redis Database):RDB保存某一个时间点之前的快照数据. AOF(Append-Only File):指所有的命令行记录以r ...