Build 2018大会:C#的未来

在C#的未来特性清单上,排在第一位的是可空引用类型。我们第一次报道这个特性是在去年,这里我们简要的回顾一下:所有的引用变量、参数和字段默认都是非空的。然后,和值类型一样,如果你希望它们可以为空,你就必须在类型名上加一个问号(?)来显式说明。

这会是一项可选特性,目前的想法是,对于将升级到C# 8的现有项目,可空引用类型特性是关闭的。对于新项目,微软倾向于默认开启这项特性。

警告会进一步分成潜在错误和表面警告。例如,如果p.MiddleName是一个string?,那么下面这行代码会是一个表面警告:

string middleName = p.MiddleName;

由于危险只会出现在值解引用的时候,所以这种对局部变量的赋值并不是一个真正的问题。因此,你可以在遗留代码上禁用这个警告,以减少误报数量。

同样,早于这项特性的库也不会触发警告,因为编译器不知道一个指定的参数是否应该视为可空的。

GitHub上提供了可空引用类型的预览

Switch表达式

Switch块通常用于简单地返回单个值。在这个常见的场景中,其语法比实际完成的工作要复杂得多。考虑下下面这个使用模式匹配的例子:

static string M(Person person) { switch (person) { case Professor p: return $"Dr. {p.LastName}"; case Studen s: return $"{s.FirstName} {s.LastName} ({s.Level})"; default: return $"{person.FirstName} {person.LastName}"; } }

在新的提案中,反复出现的case和return语句可以省掉,其结果是下面这种更新、更紧凑的语法:

static string M(Person person) { return person switch { Professor p => $"Dr. {p.LastName}", Student s => $"{s.FirstName} {s.LastName} ({s.Level})", _ => $"{person.FirstName} {person.LastName}" }; }

具体的语法还在讨论之中。例如,现在还不确定这个特性是要使用=>还是:分割模式表达式和返回值。

Property模式匹配

当前,可以通过when子句执行Property层的模式匹配。

case Person p when p.LastName == "Cambell" : return $"{p.FirstName} is not enrolled";

借助“Property模式”,上述代码就简化为:

case Person { LastName: "Cambell"} p : return $"{p.FirstName} is not enrolled";

变化很小,但却让代码更清晰,也去掉了一些冗余的变量名称。

从模式中提取Property

更进一步,你可以在模式中声明变量:

case Person { LastName: "Cambell", FirstName: var fn} p : return $"{fn} is not enrolled";

模式中的“解构器(Deconstructor)”

解构器用于把对象解构成其组成部分。它主要用于从元组多重赋值。在C# 7.3中,你还可以把解构器和模式匹配一起使用。

在下面的例子中,Person类被解构成{FirstName, MiddleName, LastName}。由于我们不使用MiddleName,所以我们使用一条下划线来跳过这个属性:

case Person ( var fn, _, "Cambell" ) p : return $"{fn} is not enrolled";

递归模式

下一个模式,假设Student类解构成{FirstName, MiddleName, LastName, Professor}。我们可以同时解构Student对象及其子类Professor对象。

case Student ( var fn, _, "Cambell", var (_, _, ln) ) p : return $"{fn} is enrolled in {ln}’s class";

在这行代码中,我们:

把student.FirstName提取到fn

跳过student.MiddleName

把student.LastName匹配成“Cambell”

跳过student.Professor.FirstName和student.Professor.MiddleName

把student.Professor.LastName提取到ln

GitHub上提供了递归模式匹配的预览

索引表达式

索引表达式消除了在使用类数组数据结构时的大部分冗长(易出错)的语法。

帽子操作符(^)从列表尾部开始计数。例如,要获取字符串的最后一个值可以这样写:

var lastCharacter = myString[myString.Length-1];

或者简单地写成:

var lastCharacter = myString[^1];

该特性适用于计算值,如:

Index nextIndex = ^(x + 1); var nextChar = myString[nextIndex]

范围表达式

范围表达式和索引表达式密切相关,用(..)操作符表示。下面是一个简单的例子,获取字符串中的前三个字符:

var s = myString.Substring[0..2];

范围表达式可以结合索引表达式一起使用。在下面这行代码中,我们跳过了第一个和最后一个字符。

var s = myString.Substring(1..^1);

范围表达式也适用于Span。

Span<int> slice = myArray[4…8];

注意,第一个数值包含,第二个数值不包含。因此,变量slice包含元素4、5、6、7。

要获取一个切片,包含从某个索引值往后的所有元素,有两种方法:

Span<int> rest = myArray[8..]; Span<int> rest = myArray[8..^0];

类似地,你可以省略第一个索引:

Span<int> firstFour = myArray[..4];

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/1751138c8ab356e91d3a362def038209.html