C#8.0 可空引用类型
介绍
我们的项目代码运行时最频繁的错误之一就是 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()
,此构造函数会使Name
和Adress
属性为null,所以分析器发出了CS8618的警告。
我们将空构造函数写上,此时警告智能的转移到构造函数上了。
我们在构造函数中将可能为null的string类型属性附上值,警告消除。而string?类型无需处理,因为它是允许为null的。
以上两种方式也可以消除警告。
在GetStudentNames
方法中,我们使用Student
的EnglishName
属性时,分析器发出了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
方法返回Student
的Adress
属性,分析器并没有发出警告,因为分析器通过[NotNull]
特性也知道了Adress
属性的值永远不会为null。
我们尝试将Adress
属性改为可能返回null值,分析器立马发出了CS8603警告,很给力。
[NotNullIfNotNull]
这个特性作用于方法中,用于告诉其他程序员只要你不给我的方法传null参,我就不会返回null给你,你看着办。
[return: NotNullIfNotNull("student")]
public string? GetStudentAdress(Student? student)
{
return student?.Adress;
}
adress
和adress2
有着不同的待遇。
缺陷
有些场景分析器无法分析出潜在的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()
中的FirstName
和 LastName
运行时为 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
,而s
和s2
是不可为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(文档站点在规划中,会慢慢完善起来):
QQ群:7424099
微信群:加技术运营微信(MasaStackTechOps),备注来意,邀请进群
------ END ------
作者简介
**吴炜来:**MASA技术团队成员。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
手把手教你玩 MySQL 删库不跑路,直接把 MySQL 的 binlog 玩溜!
我们常常听人说,只要你愿意,MySQL 可以恢复至半个月甚至一个月以内的任何一个状态。网上也有很多删库跑路的段子。。。 那么今天松哥想和大家来聊一聊 MySQL 中的 binlog,来手把手教大家如何利用 binlog 来恢复 MySQL 中的数据,这样,以后要是不小心删库了,那也不用跑路了。 MySQL 中的日志比较重要的有 binlog(归档日志)、redo log(重做日志)以及 undo log,那么跟我们本文相关的主要是 binlog,另外两个日志松哥将来有空了再和大家详细介绍。 1. binlog binlog 我们中文一般称作归档日志,如果大家看过松哥之前发的 MySQL 主从搭建,应该对这个日志有印象,当我们搭建 MySQL 主从的时候就离不开 binlog(传送门:MySQL8 主从复制踩坑指南)。 binlog 是 MySQL Server 层的日志,而不是存储引擎自带的日志,它记录了所有的 DDL 和 DML(不包含数据查询语句)语句,而且是以事件形式记录,还包含语句所执行的消耗的时间等,需要注意的是: binlog 是一种逻辑日志,他里边所记录的是一条 SQL ...
-
下一篇
为何选择EdgeX?
平台架构 开发人员、技术提供商和最终用户能够通过技术、资源共享和 EdgeX 生态系统的规模经济(无论是其自己的实践,还是通过向他人提供商业化的“ EdgeX 就绪型”解决方案),以更低的成本和风险加速实现业务价值。 EdgeX 在许多方面都独具特色,比如服务范围、广泛的行业支持、可信度、投入,以及由 Linux 基金会旗下 LF Edge 组织所提供的不受供应商限制的 Apache 2.0 开源许可模式。 EdgeX 本身也是在所有垂直市场物联网用例和企业中推动数字转型与 AI 技术发展的核心要素。 项目服务范围 EdgeX Foundry 专注于充分运用云原生原则(例如,松耦合的微服务、平台独立性),以及实现满足特定物联网边缘需求的架构(包括不同的连接协议、广泛分布的计算节点的安全性和系统管理,以及缩减高度受限的设备规模),借此发挥边缘计算的优势。 该项目的“甜蜜点”在于,用例中的本地决策可以实时或以近乎实时的速度进行制定,与此同时,自动化和操作由多个数据源提供支持。在这里, EdgeX 可以解决边缘节点和数据规范化(比如,在分布式物联网边缘架构中需满足“南正对北、东正对西”...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- MySQL数据库在高并发下的优化方案
- Docker安装Oracle12C,快速搭建Oracle学习环境
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- MySQL8.0.19开启GTID主从同步CentOS8
- Hadoop3单机部署,实现最简伪集群