C#8.0 可空引用类型
介绍
我们的项目代码运行时最频繁的错误之一就是 System.NullReferenceException 异常,c#8.0 增加的可为空引用类型就是用来帮助开发者降低甚至消除 NULL 异常。我们需要注意的是可空引用类型是语法级别的功能,也就是代码编写的时候就会受到编程约束,这个与可为空值类型是不一样的。项目支持 c#8.0 请参见C# 语言版本控制。
目录
在项目中启用可空引用类型支持
在项目文件中增加<Nullable>enable</Nullable>
后,项目代码中的引用类型将被解析拆分为不可空引用类型和可空引用类型。
将警告提升为异常
可空引用类型功能是以警告的形式出现,并不会干扰项目生成编译,约束力较弱。如果想严格要求自身,那我们可将特定的警告变为异常来提升约束力。
相关技术文档C# 编译器选项 - 错误和警告 | Microsoft Docs,Non-nullable references with C# 8 and .NET Core 3.0 · Cezary Piątek Blog (cezarypiatek.github.io),大家在编写代码时遇到 Microsoft.CodeAnalysis.CSharp 分析器所给的警告代码,都可按照自己的要求将其变为异常来约束自己。
将变量标注为可空引用类型
我们平时使用的引用类型属于不可空引用类型,在其后附加**?便为可空引用类型**。
泛型
使用示例
如上示例,由于 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 给你,你看着办。
adress
和adress2
有着不同的待遇。
缺陷
有些场景分析器无法分析出潜在的 null 异常
Struct
default(FirstName)
和new Student()
中的FirstName
和 LastName
运行时为 null,编辑器此时未出现任何警告。
属性 Bar
在运行时为 null
,而s
和s2
是不可为 null 字符串类型,编辑器此时未出现任何警告。
数组
数组也是可为 null 的引用类型中的已知缺陷
代码中的数组声明其元素为不可为 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 技术团队成员
版权声明: 本文为 InfoQ 作者【MASA技术团队】的原创文章。
原文链接:【http://xie.infoq.cn/article/0cff6b1eaaee1b2a603429559】。文章转载请联系作者。
评论