C# 8中的可空引用类型
原文:Nullable Reference Types In C# 8
作者:.NET Core Tutorials
译者:Lamond Lu

现状
可空引用类型?
自从我开始学习.NET, 引用类型一直就是可空的。然而初级程序员通常会告诉你值类型不可空,引用类型可空。
事实上,在.NET中有一种语法可以表明一个值类型是否可空。
int? nullableInt1 = null;
Nullable<int> nullableInt2 = null;
int nullableInt3 = null; //编译错误
并且这种语法并不只适用于原始类型,它也适用于struct
Tips: Struct本身就是值类型
struct MyStruct
{
}
static void Main(string[] args)
{
MyStruct? mystruct1 = null;
MyStruct myStruct2 = null;
}
但是现在我们希望在编译以下代码时,编译器能给出错误或者警告
class MyClass
{
}
static void Main(string[] args)
{
MyClass myClass = null;
}
为什么?
这里我们第一个问题就是,为什么需要让编译器给出错误或者警告?
我们接下来已一段简单的代码为例。
class MyClass
{
public void SayHello()
{
Console.WriteLine("Hello");
}
}
static void Main(string[] args)
{
var myClass = new MyClass();
myClass.SayHello();
}
这个代码是某个功能的最初版本,看起来非常的简单,并且会运行的很好。
现在我们想象一下,一段之间之后,另外一个程序员加入了项目,将程序修改如下
class MyClass
{
public void SayHello()
{
Console.WriteLine("Hello");
}
}
static void Main(string[] args)
{
var myClass = new MyClass();
...
if (true)
{
myClass = null;
}
...
if(myClass == null)
{
...
}
...
myClass.SayHello();
}
这样的代码看起来很傻,但是现实情况中确实会发生,有人会将myClass设置为null来满足他们正在处理的功能。它深藏在程序中,甚至可以通过单元测试,所有的功能看起来都运行良好。
但是在某个特定的时间点, 特定的条件下,程序会抛出一个NullReferenceException空引用异常, 这时候我们才会发现我们缺少了空引用判断,然后添加一定的防护。
class MyClass
{
public void SayHello()
{
Console.WriteLine("Hello");
}
}
static void Main(string[] args)
{
var myClass = new MyClass();
...
if (true)
{
myClass = null;
}
...
if(myClass == null)
{
...
}
...
if(myClass != null)
{
myClass.SayHello();
}
}
那么如何避免其他程序员,或者未来的自己,陷入这种空引用的陷阱呢?
启用可空引用类型
如上所述,这里我们首先需要使用C#8的Nullable Reference Types功能。 完成后,只需要在项目的csproj文件中添加一行:
<NullableReferenceTypes>true</NullableReferenceTypes>
就可以了。
编译器产生警告
一旦我们启用了该功能,让我们看一段简单的代码来说明它是如何工作的。
class MyClass
{
public void SayHello()
{
Console.WriteLine("Hello");
}
}
static void Main(string[] args)
{
MyClass myClass = null;
myClass.SayHello();
}
如果编译以上代码的话,我们会得到2个警告。这里我使用了加粗字体,是因为我们得到的只是警告,不是编译错误。你的程序依然可以编译和启动。
第一个警告是我们尝试将null分配给未明确设置为允许空值的变量。
Converting null literal or possible null value to non-nullable type.
第二个警告是当我们尝试实际使用非可空类型时,编译器认为它将为null。
Possible dereference of a null reference.
所以这两个警告都不会阻止我们的应用程序运行,但它会警告我们我们可能遇到麻烦。
下面让我们修改代码,让我们的引用类型变量可空
C# 8中可用引用类型的定义于可空值类型一样,即在声明时,类型名的后面加?号
static void Main(string[] args)
{
MyClass? myClass = null;
myClass.SayHello();
}
这里有趣的是,修改完代码后,编译项目,你依然会收到Possible dereference的警告。为了消除掉这个警告,你可以添加空引用检查。
static void Main(string[] args)
{
MyClass? myClass = null;
if (myClass != null)
{
myClass.SayHello();
}
}
至此,所有的警告都消失了。
编译器警告的限制
在我们实际编码过程中,引用类型可以在方法,类,甚至程序集中传递。因此抛出警告时,它并不是万无一失的。例如,我们有如下代码:
class MyClass
{
public Random Random = new Random();
}
static void Main(string[] args)
{
MyClass myClass = new MyClass();
SomeMethod(myClass);
var next = myClass.Random.Next(1, 10);
}
static void SomeMethod(MyClass myClass)
{
myClass.Random = null;
}
这里编译器只会警告我们在分配一个null值给一个没有明确指定可空的变量。但是我们不会得到Possible dereference的警告。这里我们可以推断,一旦将对象传递到方法之外,无论在那里发生什么(如设置null),我们都不会被警告。但是如果我们在相同的代码/方法块中如此明确地分配null,然后尝试使用它,那么编译器将尝试给我们一个帮助。
为了与上述代码比较,以下代码确实会收到2条警告
static void Main(string[] args)
{
MyClass myClass = new MyClass();
if (new Random().Next(1, 10) > 5)
{
myClass = null;
}
myClass.SayHello();
}
启用可空引用类型的严格模式
如果你希望用错误替换警告,你可以升级整个检查到严格模式。这里你只需要在项目的csproj文件中添加一行:
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
注意: 这会将所有警告视为错误,而不仅仅是关于空引用问题的警告。但这意味着如果有警告被抛出,你的项目将不再编译!
C# 8中的可空引用类型的更多相关文章
- 迫不及待地体验了一把 C#8.0 中的可空引用类型(Nullable Reference)
在我之前的一篇博客 NullReferenceException,就不应该存在! 中,我吐槽了 C# 中 null 的弊端以及避免 null 的方法:事实上这本都是现代高级语言中极力推崇的做法.Kot ...
- C#8.0 可空引用类型
介绍 我们的项目代码运行时最频繁的错误之一就是 System.NullReferenceException 异常,c#8.0增加的可为空引用类型就是用来帮助开发者降低甚至消除NULL异常.我们需要注意 ...
- 快速了解C# 8.0中“可空引用类型(Nullable reference type)”语言特性
Visual C# 8.0中引入了可空引用类型(Nullable reference type),通过编译器提供的强大功能,帮助开发人员尽可能地规避由空引用带来的代码问题.这里我大致介绍一下可空引用类 ...
- JavaScript中值类型和引用类型的区别
JavaScript的数据类型分为两类:原始类型和对象类型.其中,原始类型包括:数字.字符串和布尔值.此外,JavaScript中还有两个特殊的原始值:null和undefined,它们既不是数字也不 ...
- C# 可空引用类型
可空引用类型是C#8.0计划新增的一个功能,不过已经发布了预览版本,今天我们来体验一下可空引用类型. 安装 您必须下载Visual Studio 2017 15.5预览版(目前最新发布版本是15.4) ...
- C#8.0可空引用类型的使用注意要点
最近VS2019正式版发布了,装下来顺便试用了一下C#8.0,最大的看点应该就是可空引用类型了.不过C#8.0仍然处于Beta的状态,而且试用时也遇到了几个坑. 背景知识说明: 所谓的可空引用类型是指 ...
- C#中值类型和引用类型的差别浅记
C#中值类型和引用类型的差别浅记 在C#中,变量的类型分为两种.各自是值类型和引用类型. 值类型的变量直接存储值,说得更详细一些,就是值类型变量在内存中直接存储它们自身 ...
- C#8.0—非空引用类型
非空引用类型--C#8.0 原文地址:https://devblogs.microsoft.com/dotnet/try-out-nullable-reference-types/?utm_sourc ...
- 何修改WAMP中mysql默认空密码--转
何修改WAMP中mysql默认空密码 http://www.cnblogs.com/hooray/archive/2011/07/23/2114792.html WAMP安装好后,mysql密码是为 ...
随机推荐
- 2018-2019-2 网络对抗技术 20165319 Exp3 免杀原理与实践
免杀原理及基础问题回答 免杀原理: 免杀指的是一种能使病毒木马免于被杀毒软件查杀的技术.由于免杀技术的涉猎面非常广,其中包含反汇编.逆向工程.系统漏洞等黑客技术,所以难度很高,一般人不会或没能力接触这 ...
- Little Sub and Isomorphism Sequences ZOJ - 4089
ZOJ - 4089 思路:可以反正 最长重构序列必然符合 此模式 x + { } 与 { } + x 那么 题意转化为了 找两个距离最长的相同的数.eeee 先离散化 然后 ...
- (二)stm32f103~~GPIO基本操作二(按键)
GPIO基本配置之按键输入操作(通过按键控制小灯的翻转) KEY0 对用端口PE4,KEY1 对用端口PE3,这两个按键是一段接地,另一端接单片机.KEYWKUP 对用端口PA0,这个按键是一段接高电 ...
- wsl 子系统 用户目录位置
C:\Users\DELL\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu18.04onWindows_79rhkp1fndgsc\LocalS ...
- tar解压到指定目录
对于tar.gz的压缩包,压缩参数是tar xvzf 指定解压路径为/tmp则为: tar xzvf xxx.tar.gz -C /tmp 注意/文件夹必须存在.
- 单调栈&单调队列入门
单调队列是什么呢?可以直接从问题开始来展开. Poj 2823 给定一个数列,从左至右输出每个长度为m的数列段内的最小数和最大数. 数列长度:\(N <=10^6 ,m<=N\) 解法① ...
- jdk12+tomcat9 配置
jdk12 没有了jre的配置 直接配置path就可以了 tomcat常规配置,只是启动的时候麻烦一点 需要重新写入jdk jre jvm 到server.bat文件 参考文章: https: ...
- C#线程--5.0之前时代(一)--- 原理和基本使用
一.开篇概念明晰: 多任务: 协作式多任务:cpu可以处理多种任务,但是这些任务是排队等候的,当cpu在处理一个任务的时候,其他的任务被锁定,只有当cpu处理完当前任务,才可以继续处理下一个任务(专一 ...
- LeetCode 15 3Sum [sort] <c++>
LeetCode 15 3Sum [sort] <c++> 给出一个一维数组,找出其中所有和为零的三元组(元素集相同的视作同一个三元组)的集合. C++ 先自己写了一发,虽然过了,但跑了3 ...
- 30 ArcGIS 许可管理器常见问题(持续更新中……)
一.[单机版] 1.1.ArcMap 1.2.ArcGIS Pro 错误一 ArcGIS Pro单机许可安装授权,在Configure Authorization界面报“This functional ...