微软提议在C# 7中为引用增加选项类型
英文原文:A Proposal to Add Option Types for References to C# 7
微软 C# 语言的项目经理 Mads Torgersen,最近提议在C# 7 中引入可为选项类型(option types)的引用类型。加入选项类型能让 C# 语言变得更安全,正如 Torgersen 所说,在 C# 里,因为任一引用类型都能引用一个空值,从而导致了空引用异常的泛滥成灾,而使用选项类型能减少空引用异常的产生。
C#已经对 nullable 值类型提 供了支持,即对基于 struct 的已提供了支持,但不支持基于 class 的引用类型。对一门现存的已然成熟的编程语言事后加入选项类型,这其中存在着巨大的复杂性,出于这一原因,Torgersen 不打算建立一套“滴水不漏的”机制,而是在检测到代码可能存在解引用空值的时候发出警告信息。
新的提议方案对一个现有的引用类型T有如下约定:
- T 用来表示一个非 nullable 类型;
- T?用来表示一个 nullable 引用类型;
- 在以下情况下,编译器将发出告警信息:
- 一个 nullable 的
T?类型被解引用或者转化为一个非
nullable 类型; - 将 null/default (T)赋值给非 nullable T 类型变量;
- 流分析检测到一个 nullable 引用很可能不再是空值;
- 构造函数在返回前未对非 nullable 引用进行赋值;
- 构造函数使用尚未赋值的非 nullable 引用。
另一方面,当一个非 nullable 数组在进行初始化时,无法确保其中为 null 的数组成员不被保留下来。
使用空条件操作符(null-conditional operator)?.,可参考介绍C# 6,将产生以下效果:
string s; string? ns = SomeStringMaybe (); s = ns; // emits warning if (ns != null) { s = ns; } // ok WriteLine (ns.Length); // emits warning WriteLine (ns?.Length); // ok
尽管使用这种新设计出的方法不用改动任何 的现有代码,但该方法仍可能对编译器的行为产生潜在的影响,因为在当前的 C# 里,T实际上用来表示一个 nullable 类型。因此,Torgersen 说,需要另外再新增一套机制来关闭告警信息,用于确保在跨 C# 版本和程序集下的编译兼容性。
需要重点声明的是,当所赋的值为 null 时,若编译器只产生告警信息,那么C# 7 仍将会允许一个非 nullable 类型T包含 null 类型,这主要是出于对程序集兼容性的考虑。这也使得C# 7 表现得与其他编程语言大相径庭,比如 Swift option types 和 Haskell Maybe,在 Swift 和 Haskell 中,选项类型可被视为对基本类型的一种封装(实际上,在 Swift 里选项类型就是泛型类型,在 Haskell 里就是 monad)。
从通告的评论来看,人们对微软的提议反应不一。有些人担心在重新定义了类型T为非 nullable 之后,现存的 C# 代码会产生大量的对他们来说毫无意义的告警信息。还有些人认为应该用T!或者其他不同于基本类型T的表示方式来表征非 nullable 类型,基本类型T继续用来表示 nullable 类型。
微软的提议方法没有让任何已有的代码受益,应对其进行重构以使其有助于代码的 non-nullability。另外有部分人支持该提议,并表示自己更喜欢这种“严谨的”模式,在这种模式下,空值经由 option<T>或其它等效结构被有效地封装了起来。