PCon全球产品创新大会最新日程一览,这里直达 了解详情
写点什么

C#将引入可空的引用类型

  • 2017 年 4 月 20 日
  • 本文字数:1360 字

    阅读完需:约 4 分钟

是的,标题没错。C#其中一份新提案假定,所有的引用类型在默认情况下都是不可空的。在新语法下,你需要显式地标明一个引用变量是可空的,就像对值类型所做的那样。

和值类型一样,T 是指不可空类型,而 T? 是指可空类型。以下情况会产生警告:

  • 取消对可空变量的引用;
  • 一个可空变量或参数被赋值给一个不可空变量;
  • 从 T?[] 转换到 T[];
  • 从 T[] 转换到 T?[];
  • 将一个空字面量赋值给一个不可空变量或参数;
  • 构造函数没有给所有的不可空字段赋值;

对于前两种情况,如果你使用了感叹号运算符(x!)或者编译器能够证明已经执行了 null 检查,那么警告将被忽略。

实现细节

底层编译器将会忽略可空注解,因此,那不是问题。不过,在程序集级,应该有某种标记,可以说明库在编译时启用了可空注解。

由于所有这类可空的东西从技术上讲都是一种破坏性修改,所以当前的计划是允许开发人员选择下面的类别:

  • 可空警告;
  • 不可空警告;
  • 警告来自其他文件中的注解。

提案继续写道:

选择参与的粒度表明,这是一个类似分析器的模型,大段的代码通过编译指令选择参与和退出,用户可以选择安全级别。此外,每个库的选项(“在准备好应对后果之前,忽略 JSON.NET 中的注解”)可以表示为代码中的属性。

根据预期,这种设计要达到以下三个目的:

  • 用户可以像他们希望的那样逐步采用可空属性检查;
  • 库作者可以添加可空属性注解,而不必担心破坏用户的代码;
  • 除此之外,没有“配置噩梦”之感。

对于同一个方法,你不必进行可空和不可空的重载。虽然从技术上讲,CLR 支持这样做,但那不是 CLS 或者通用语言规范的组成部分。这意味着,大多数编译器都会不知道发生了什么。HaloFour 作了如下说明:

modreq不是 CLS。modopt确实支持重载,但需要具体了解所有重要编译器的这个部分,因为至少要将修饰符复制到调用签名里。两者都会破坏与现有方法签名的兼容。对于希望在整个 BCL 快速传播的东西来说,使用modopt会成为巨大的障碍。

泛型

在使用泛型时,以下情况会出现额外的警告:

  • 从 C转换到 C<T?>,除非类型参数是协变量(出);
  • 从 C<T?> 转换到 C,除非类型参数是反变量(入);
  • 使用 C<T?>,然后将类型参数限制为不可为空。

使用“class”,则泛型强制非空。使用“class?”则允许空值。该提案继续写道:

如果一个类型参数没有约束,或者只有可空约束,则情况会稍微复杂一些:这意味着,相应的类型参数既可以为空,也可以不为空。在那种情况下,安全的做法是将类型参数既作为可空参数来处理,又作为不可空参数来处理,任何一个不满足,就发出警告。

数组

数组是一项特殊的挑战,因为在一个不可为空的数组中,不一定可以确保每个槽都有一个值。

对于一个非空引用数组,我们无法通过充分地跟踪来保证数组的所有元素都被初始化。不过,在从数组读取数据或者传递数组之前,如果新创建的数组没有元素被赋值,我们就会发出警告。那应该可以处理常见的情况,而又不带来太多干扰。

开放性设计问题

使用 default(T) 应该发出警告吗?还是说假定它会返回 T?,而不是 T?

可以删除局部变量上的? 而根据使用情况推断其可空性吗?

参数可以使用 T! x 模式自动生成 null 检查吗?

可以调整一下可空值类型,以便让开发人员可以使用 x.method 代替 x.Value.method 吗(这用在当 x 已知非空时,比如已经成功完成了 null 检查)?

更多信息

查看英文原文: C# Futures: Nullable Reference Types

2017 年 4 月 20 日 18:161420
用户头像

发布了 1008 篇内容, 共 329.9 次阅读, 收获喜欢 301 次。

关注

评论

发布
暂无评论
发现更多内容

不要被数据蒙蔽你的眼睛

好奇分析

数据分析 统计学 辛普森悖论

复盘健康

将军-技术演讲力教练

Dubbo框架学习笔记七

风翱

dubbo 12月日更

RTO, RPO是啥?是割韭菜的意思么?

Java领域老程

数据库 编程 程序员 数据结构 后端

🏆【CI/CD技术专题】「Docker实战系列」(1)本地进行生成镜像以及标签Tag推送到DockerHub

浩宇天尚

Docker 容器镜像 12月日更 12 月日更 Dockerhub

字节秋招二面把我干懵了,问我SYN报文什么情况下会被丢弃?

程序员小毕

Linux 程序员 面试 程序人生 网络

网络安全教程:13 信息收集

喀拉峻

黑客 网络安全 安全 信息安全

如何看待制造企业的数字化转型,有哪些成功案例可以分享?

优秀

低代码 数字化转型 制造业

GrowingIO Reactor速成指南

GrowingIO技术专栏

响应式编程 reactor

深入浅出Mysql索引优化专题分享|面试怪圈

Java领域老程

Java MySQL 数据库 编程 程序员

花一点时间优化一次年迈的后台系统的检索体验

为自己带盐

28天写作 12月日更 ​jQuery

☕【Java深层系列】「技术盲区」让我们一起完全吃透针对于时间和日期相关的API指南

浩宇天尚

Java 工具 日期处理 12月日更 12 月日更

跟着源码学IM(九):基于Netty实现一套分布式IM系统

JackJiang

Netty websocket 即时通讯 IM

【架构实战营】模块七

Henry | 衣谷

架构实战营

JavaScript面试系列:JavaScript设计模式之桥接模式和懒加载

Jerry Wang

JavaScript 设计模式 桥接模式 28天写作 12月日更

动手做个 AI 机器人,帮我回消息!

程序员鱼皮

JavaScript AI 前端 nlp Node

springboot-如何开启debug日志?

Java领域老程

Java 编程 程序员 数据结构 springboot

如何提高用户留存?

石云升

AARRR 产品思维 28天写作 产品增长 12月日更

聊聊你每天是如何修bug的

卢卡多多

bug修复 28天写作 12 月日更

vivo:不做开发者的过客,变成IoT的归人

脑极体

【精通Linux系列】服务器之间的telnet与scp命令用法,进程管理命令之ps -ef与ps aux详解

Java领域老程

Linux 编程 程序员 后端

王者荣耀异地多活架构设计

Beyond Ryan

vue3.2组件库-element plus 自动按需引入

Mr.Cactus

typescript Vue3 Element Plus Vite2

PassJava 开源(一) :初始化项目和添加微服务

悟空聊架构

SpringCloud 28天写作 passjava 悟空聊架构 12月日更

在 IDEA 中使用 Debug,简直太爽了!

Java领域老程

Java 编程 程序员 后端

十二张图带你了解 Redis 的数据结构和对象系统

程序员历小冰

redis 数据结构 28天写作 12月日更

Linux操作系统里一个进程最多可以创建多少个线程?

程序员小毕

Linux 程序员 面试 程序人生 架构师

Python 的切片为什么不会索引越界?

Python猫

Python

如何正确的重写hashcode()

李子捌

Java 28天写作 12月日更

解决:Command ‘mongo‘ not found, but can be installed with

liuzhen007

28天写作 12月日更 12 月日更

C#将引入可空的引用类型-InfoQ