C# 8.0可空引用类型的使用注意记录

前言

最近VS2019正式版发布了,装下来顺便试用了一下C#8.0,最大的看点应该就是可空引用类型了。不过C#8.0仍然处于Beta的状态,而且试用时也遇到了几个坑。

背景知识说明:

所谓的可空引用类型是指,一旦启用了可空引用类型这个新特征,引用类型将默认被视为不可空,无法赋予null,除非手工将它设为可空引用类型。

实战示例:

首先是新建一个C#的项目,在 项目文件(.csproj)里加入两行配置,目的是启用“C#8.0语言”和“可空引用类型”:

<LangVersion>8.0</LangVersion>
<NullableContextOptions>enable</NullableContextOptions>

整个文件看起来是这样的:

这样就算是整个项目全局启用了可空引用类型了。

注意:

在VS2019正式版中,使用

<NullableContextOptions>enable</NullableContextOptions>

而不是使用

<NullableReferenceTypes>true</NullableReferenceTypes>

后者在正式版中已经失效了。

如果不希望全局启用可空引用类型的话,可以在程序代码中加入以下编译指令:

#nullable enable

这样可以在加入了该指令的文件中,单独启用可空引用类型。但是,极度不推荐这种做法。为什么呢?因为该指令仅仅在该文件中有效,不能跨文件生效,从而无法阻止null逃逸到使用了该指令的文件中,也就是说,用了也等于没用。

一个很简单的例子足以证明:

注意上面项目文件中并没有全局启用可空引用类型,而下面的Class1.cs中使用了编译器指令来单独启用可空引用类型。

从运行结果可见,空引用仍然逃逸到使用了该指令的作用域中了。别说编译错误,连编译警告都没有。完全达不到理想的效果。

因此,强烈建议在项目文件中全局启用可空引用类型,而不是在某个源文件中单独使用。

另外,还有一点要注意的是,即使启用了可空引用类型后,默认情况下,即使对不可空引用赋予null,编译器也只会生成编译警告,而不是编译错误。仍然是能够编译通过的。一个大项目中,编译警告不可避免,甚至可能会很多,从而淹没了“给不可空引用类型赋予空值”这种不起眼的警告。

因此,建议将特定的警告视为错误。警告编号为8600、8625、8618、8604,或者将所有警告视为错误。具体是在项目文件中加入以下设置(见图一):

<WarningsAsErrors>8600 8625 8618 8604</WarningsAsErrors>

或者在项目编辑器中设置也可以:

这是我自己测试得出的结果,可能还有其它潜在的相关警告编号我没有测试出来。如果有谁知道的话,告诉我一下,谢谢。

做好这些配置之后,可以看到引用类型默认都不能赋予空值了:

这时候普通的引用类型的变量和参数都不能设为null了。

这样可以防止空值扩散开来,引起恼人的空引用异常。

但是,这里有个坑需要注意!!!!

struct里不适用可空引用的规则!!

struct里不适用可空引用的规则!!

struct里不适用可空引用的规则!!

这种情况下直接运行,仍然会抛出空引用异常!!!C#8.0仍未能完全封堵住空引用的逃逸。

其实我还是比较赞同用不可空引用类型的方案的,而不是可空引用类型的方案。毕竟我想要的,只不过是一个不可空的断言,只是想利用不可空引用来划分安全边界,从而防止空值的扩散。简单来说就是想将变量和参数明确声明为不可空引用类型。因为历史和现实的原因,大量的库都还没能全面使用可空引用类型。这种情况下,只有我使用可空引用类型,是不靠谱的。无法划分安全边界。

然而C#选择了可空引用类型的方案,而且还不是强制启用,而且默认只是警告。。跟没有一样。。。

比方说,我使用了一个第三方库项目,而空值的来源是正好是该库项目的,而我对这个库并没有源代码或者修改权限。这时候就无法阻止空值逃逸到我的项目中了。

还是之前的代码,只是稍微做一下修改。新增了一个库项目ClassLibrary1,这个库并没有使用可空引用类型。

库的代码如下:

很简单,就是LibClass3.GetInstance()本应该返回LibClass2的实例,但是出于某种原因,返回了null。但是我的项目中使用了LibClass2和LibClass3。我的项目是全局启用了可空引用类型的:

编译正常,毫无警告和错误。一旦运行,则抛出空引用异常:

可见,目前来说,C#8.0的可空引用类型并不能解决外源性的空值扩散,只能解决内源性的空值扩散,无法跨模块生效。还是洗洗睡吧。

参考资料:

https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/nullable-types/index

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/nullable-reference-types-specification

https://github.com/dotnet/roslyn/blob/master/docs/features/nullable-reference-types.md

https://www.youtube.com/watch?v=VdC0aoa7ung

https://stackoverflow.com/questions/54852880/what-is-the-difference-between-nullablecontextoptions-and-nullablereferencetypes

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。

(0)

相关推荐

  • C#基础语法:可空类型详解

    以下是System.Nullable<T>在FCL中的定义. [Serializable, StructLayout(LayoutKind.Sequential)] public struct Nullable<T> where T :struct { private Boolean hasValue= false; internal T value= default(T); public Nullable(T value) { this.value= value; this.ha

  • 浅谈C# 中的可空值类型 null

    C# 不允许把 null 赋给一个值类型的数据.在 C# 中,以下语句是非法的: 复制代码 代码如下: int a = null;    // 非法 但是,利用 C# 定义的一个修饰符,可将一个变量声明为一个可空(nullable)值类型.可空值类型在行为上与普通值类型相似,但可以将一个 null 值赋给它.如下所示: 复制代码 代码如下: int? a = null;      // 合法 当把一个变量定义为可空值类型时,该变量依然可以被赋值为 0,代码如下所示: 复制代码 代码如下: usi

  • C#可空类型用法分析

    本文实例讲述了C#可空类型用法.分享给大家供大家参考.具体分析如下: 可空类型只能用于值类型,不能用于引用类型,引用类型本身支持null值. 如果直接把null赋值给int类型,会出现一个错误"无法将 NULL 转换成'int',因为它是一种值类型". 赋值时应该使用 int? a = null; 可空类型与一元或二元运算符一起使用是,如果一个操作数或两个操作数都是null,其结果为null. 说白了int?a=null 这句话的意思就是让值类型a可以接收null这个值 举例1 int

  • C# 可空类型分析

    例如,Nullable<Int32>,读作"可空的 Int32",可以被赋值为 -2147483648 到 2147483647 之间的任意值,也可以被赋值为 null 值.Nullable<bool> 可以被赋值为 true 或 false,或 null.在处理数据库和其他包含可能未赋值的元素的数据类型时,将 null 赋值给数值类型或布尔型的功能特别有用.例如,数据库中的布尔型字段可以存储值 true 或 false,或者,该字段也可以未定义. 可空类型具有

  • C#基础知识 全面解析可空类型

    引言: C# 2.0 中还引入了可空类型,可空类型也是值类型,只是可空类型是包括null的值类型的,下面就介绍下C#2.0中对可空类型的支持具体有哪些内容(最近一直都在思考如何来分享这篇文章的,因为刚开始觉得可空类型使用过程中比较简单,觉得没有讲的必要,但是考虑到这个系列的完整性,决定还是唠叨下吧,希望对一些不熟悉的人有帮助). 一.为什么会有可空类型 如果朋友们看了我之前的分享,对于这一部分都不会陌生,因为我一般介绍C#特性经常会以这样的方式开头的, 因为每个特性都是有它出现的原因的(有一句佛

  • c#可空类型的作用说明

    可空类型用途主要是从数据库读取数据有可能为空,而不是插入使用,插入数据都要进行验证,如果要插入数据库的null,则使用DBNull.value 判断取出的数据是否为数据库中的null,如果是则赋值给可空的datetime类型的Lockdatatime 属性 tseat.Lockdatatime = reader.IsDBNull(5) ? null : (DateTime?)reader.GetDateTime(5); 判断取出的数据是否为数据库中的null,如果是则赋值给可空的int类型的Te

  • C#中关于可空类型的小知识

    1) 在与1元或二元运算符一起使用时,如果其中一个操作数为null或两个均null,则结果为null. 如: 复制代码 代码如下: int? a = null; int? b = a+3; 则b为null 2) 比较可空类型时,只要有一个操作数为null,结果就为false 如: 复制代码 代码如下: int? a = null; int? b = 8; (a>=b)将返回false 而正是因为null的可能性,所以不能随意比较一个可空类型和一个非可空类型. 3) 空接合运算符 空接合运算符&quo

  • C#难点逐个击破(8):可空类型System.Nullable

    null与void null值用来表示数据类型未被赋予任何值,它是一种引用类型:void表示没有类型,或者说是没有任何值.null与void的区别可以认为void是根本没有,而null是一个空箱子,里面什么都没有. null值只能赋值给引用类型,这里注意到string也是一种引用类型:引用类型在C中称为"指针",即存放变量位置的内存空间位置.将变量设为null,会显式地设置引用,且它本身不指向任何内存位置: null值赋给值类型将导致编译错误. void用于方法值的返回,其本质并不是一

  • C# 8.0可空引用类型的使用注意记录

    前言 最近VS2019正式版发布了,装下来顺便试用了一下C#8.0,最大的看点应该就是可空引用类型了.不过C#8.0仍然处于Beta的状态,而且试用时也遇到了几个坑. 背景知识说明: 所谓的可空引用类型是指,一旦启用了可空引用类型这个新特征,引用类型将默认被视为不可空,无法赋予null,除非手工将它设为可空引用类型. 实战示例: 首先是新建一个C#的项目,在 项目文件(.csproj)里加入两行配置,目的是启用"C#8.0语言"和"可空引用类型": <Lang

  • JavaScript中0、空字符串、'0'是true还是false的知识点分享

    最近被问到关于js中空字符串是true还是false得问题,一时间没想起来,现在在chrome的console面板上输出代码测试一下. "" == false 结果是true   在js中空字符串与0相等  即空字符串等于false 0 == false  结果是tue   比较的时候 布尔类型的转换成number类型  false 为0  true 为1 "0" == fase 结果是true  字符串准成number Boolean("0")

  • C#新特性之可空引用类型

    安装 您必须下载Visual Studio 2017 15.5预览版(目前最新发布版本是15.4),下载地址:https://www.visualstudio.com/en-us/news/releasenotes/vs2017-preview-relnotes. 安装Roslyn扩展预览版本: 下载并解压 Roslyn_Nullable_References_Preview.zip [最新版本 11/15/17]: 关闭所有运行的Visual Studio: 运行zip根目录中的 .\inst

  • php通过各种函数判断0和空

    函数对0的判断 $cast_id = 0; var_dump(strlen($cast_id)); //1 var_dump(empty($cast_id)); // true var_dump(isset($cast_id)); //true var_dump(is_null($cast_id));//false 对空的判断 $cast_id = ""; var_dump(strlen($cast_id)); //0 var_dump(empty($cast_id)); // tru

  • Vue3.0写自定义指令的简单步骤记录

    前言 vue中提供了丰富的内置指令,如v-if,v-bind,v-on......,除此之外我们还可以通过Vue.directive({})或者directives:{}来定义指令 在开始学习之前我们应该理解,自定义指令的应用场景,任何功能的开发都是为了解决具体的问题的, 通过自定义指令,我们可以对DOM进行更多的底层操作,这样不仅可以在某些场景下为我们提供快速解决问题的思路,而且让我们对vue的底层有了进一步的了解 第一步 在main.js 在src下简历对应的文件夹 import Direc

  • vue3.0项目快速搭建的完整步骤记录

    目录 一.我们要确保vue/cli版本在4.5.0以上,才能更好的支持3.0 二.通过vue/cli3创建我们的第一个项目 Router CSS 预编译 ESLint 语法校验 运行项目 升级vue 三.vue3.0相比vue2.0改进和新特性 总结 如何搭建一个vue3.0基础项目? 一.我们要确保vue/cli版本在4.5.0以上,才能更好的支持3.0 //安装最新vue/cli yarn global add @vue/cli //或 npm install -g @vue/cli 用vu

  • Vue cli3.0创建Vue项目的简单过程记录

    创建Vue项目 在要创建项目的文件夹下面打开Powershell窗口 输入命令 vue create 项目名称 选择第二项 回车后 选择是否使用历史路由 no 回车 选择 Less 回车 选择第三个 回车 选择第一个 回车 选择第一个 回车 是否保存模板 选择no 完成啦 完成 总结 到此这篇关于Vue cli3.0创建Vue项目的文章就介绍到这了,更多相关Vue cli3.0创建Vue项目内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

  • php中0,null,empty,空,false,字符串关系的详细介绍

    在一个项目中遇到了一个奇怪的问题,耗费了我不少时间都没有解决,最终调试发现是判断的问题--关于0和 ' ' (空单引号,为好看清我加了个空格)的判断,我发现 0==" 居然成立,郁闷的同时决定写个简单页面测试,发誓要将0,null,empty,空,false的关系搞的一清二楚.因为这很可能在一些关键地方使我们编写的程序,网站存在bug.特别是可能影响到登陆等特殊地方的安全性和逻辑正确性,虽然这是很基础的知识点,但很多人,包括一些高手都可能对0,null,empty,空,false的关系很模糊.所

  • C# 8.0新特性介绍

    C# 语言是在2000发布的,至今已正式发布了7个版本,每个版本都包含了许多令人兴奋的新特性和功能更新.同时,C# 每个版本的发布都与同时期的 Visual Studio 以及 .NET 运行时版本高度耦合,这也有助于开发者更好的学习掌握 C#,并将其与 Visual Studio 以及 .NET 的使用结合起来. 加快 C# 版本的发布速度 在被称为"新微软"的推动下,微软创新的步伐也加快了.为了做到加快步伐,微软开发部门将一些过去集成在一起的技术现在都分离了出来. Visual S

  • JavaScript 引用类型实例详解【数组、对象、严格模式等】

    本文实例讲述了JavaScript 引用类型.分享给大家供大家参考,具体如下: 数组 在ECMAScript中数组是非常常用的引用类型 ECMAScript所定义的数组和其他语言中的数组有着很大的区别 数组也是一种对象 创建数组 //方法一 var arr = new Array(); //方法二 var arr1 = []; 特点 数组即一组数据的集合 js数组更加类似java的map容器.长度可变,元素类型任意 数组长度随时可变!随时可以修改!(length属性) var arr1 = [1

随机推荐