写点什么

C# 7.1先睹为快(第二部分)

2017 年 6 月 12 日

天我们介绍了异步 Main 函数(Async Main)和默认表达式(Default Expressions)。我们的 C# 7.1 之旅将继续,今天要介绍的特性在建议中称为推导元组名(Infer Tuple Names)和使用泛型的模式匹配(Pattern-matching with Generics)。

推导元组名(Infer Tuple Names)

虽然开发人员不常考虑到,但是 C#中的匿名类型包括了命名推导。例如,编写如下代码时,对象 y 将具有名为 A 和 B 的属性:

复制代码
var y = new { x.A, x.B };

根据“推导元组名建议”,值元组基本具有同样的功能。

复制代码
var z1 = (A: x.A, B: x.B); // 显式名字。
var z2 = (x.A, x.B); // 推导名字。

但是匿名类型和值元组间存在着一些显著的差异:

  • 匿名类型需要属性名,属性明可以是显示指定的,也可以是推导得到的。
  • 值元组会将未命名属性标为 Item1、Item2 等。
  • 如果匿名类型具有重复的名字,那么会产生编译错误。
  • 如果值元组具有重复的显式名字,那么会产生编译错误。
  • 如果值元组具有重复的推导名字,那么推导名会被跳过。例如:(x.A, x.B, y.A) 将转化成 (Item1, B, Item3)。
  • 值元组不能使用如下保留名字:ToString、Rest、ItemN(N 是大于 0 的数字)。

C#和 VB 间有 hen 一个有意思的差别,VB 可以通过函数去推导匿名属性名。例如:

复制代码
var y = new { x.A, x.Bar() }; // 编译错误
Dim y = New With {x.A, x.Bar()} // 匿名类型{A,Bar}

该功能特性将扩展适用于 VB 元组。

但如果恰巧有一个扩展方法使用了与推导属性一样的名字,这一特性就会引发破坏性更改。在建议中进一步提出:

考虑到这一更改的破坏性有限,并且在 C# 7.0 中,交付元组的时间窗很短,兼容性委员会认为这种破坏性更改是可以接受的。

考虑泛型约束的元组名

如果存在元组名不匹配的问题,那么编译器会尽量警告编程人员。例如:

复制代码
public static (int A, int B) Test1((int A, int B) a)
Test1((A: 1, B: 2));
Test1((X: 1, Y: 2)); // 给出警告,元组名不匹配。

如果开始采用泛型约束,代码就不工作了:

复制代码
public static T Test2<t>(T a) where T : IEnumerable<(int A, int B)>
Test2(new List<(int A, int B)>());
Test2(new List<(int X, int Y)>()); // 没有警告。
</t>

当给出前的解释是,在泛型约束的条件下,编译器是不会去检查元组名的。理论上讲,编译器是可以捕获这类问题的,但是所付出的性能上的代价要远高于所得到的收益。

使用泛型的模式匹配

模式匹配是 C# 7.0 中新提供的特性。但是使用该特性时,存在设计上的缺陷。让我们看一下 Alex Wiese 给出的如下代码:

复制代码
class Program
{
static void Main(string[] args) {}
public void Send<t>(T packet) where T : Packet
{
if (packet is KeepalivePacket keepalive)
{
// 使用 keepalive 的功能代码。
}
switch (packet)
{
case KeepalivePacket keepalivePacket:
// 使用 keepalivePacket 的功能代码。
break;
}
}
}
public class Packet {}
public class KeepalivePacket : Packet {}
</t>

代码会报如下错误:“An expression of type T cannot be handled by a pattern of type KeepalivePacket.”。但如果我们将参数改为 System.Object 类型,而不是 T 类型,代码就工作正常了。

复制代码
public void Send(object packet)

C# 7.1,通过对引发模式匹配的规则进行微调,修正了这一问题。

我们改进了“模式匹配技术规范”中的一段内容,下面以粗体标出了我们所建议添加的内容:

我们认为左侧(left-hand-side)静态类型的特定组合与特定类型是不兼容的,这会导致编译时错误。我们称静态类型 E 的值与类型 T 是模式兼容的,如果存在标识转换(Identity Conversion)、隐式引用转换(Reference Conversion)、装箱转换(Boxing Conversion)、显式引用转换,或者存在从 E 到 T 的拆箱转换(Unboxing Conversion),或者 E 或 T 均为开放类型(Open Type)。如果具有类型 E 的表达式与其所匹配的类型模式中的类型并不模式兼容,就会产生编译时错误。

这被认为是一个软件问题修复问题。由于该更新是“向前不兼容”的,因此只有将编译器设为 C# 7.1,才能使用这一更新。

查看英文原文: An Early Look at C# 7.1: Part 2

2017 年 6 月 12 日 19:001766
用户头像

发布了 226 篇内容, 共 59.5 次阅读, 收获喜欢 14 次。

关注

评论

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

ARTS Week14

丽子

如何正确的关闭线程池

Rayjun

Java 线程池

架构师训练营 - 第四周学习总结

joshuamai

“双11”正成为区块链场景应用“练兵场”

CECBC区块链专委会

大数据

【薪火计划】01 - 好与坏

brave heart

管理

架构师训练营第 1 期 - 第 8 周学习总结

Anyou Liu

极客大学架构师训练营

我用 Python 找出了删除我微信的所有人并将他们自动化删除了

Python小二

Python 微信

Flutter 开发从 0 到 1(一)需求与准备

吴小龙同学

flutter ios android 跨平台

你以为只是简单的排序?(一)

书旅

golang 数据结构与算法

蘑菇街大牛熬夜整理的Spring MVC知识点总结(思维导图+源码笔记),免费分享文档资料

Java成神之路

Java 程序员 架构 面试 编程语言

这篇 MySQL 索引和 B+Tree 讲的太通俗易懂!

云流

MySQL 面试 数据库事务 索引结构

用eBPF/bcc分析系统性能的一个简单案例

AI乔治

Java 编程 架构 前端

极客时间 - 架构师一期 - 第八周作业

_

极客大学架构师训练营 第八周作业

C++的智能指针你了解吗?

良知犹存

c++

极客大学 - 架构师培训 -ch3 作业

bing5tui3

极客大学架构师训练营

在线IDE开发入门之从零实现一个在线代码编辑器

徐小夕

Java ide H5 H5制作 代码编辑器

架构师训练营第四周作业

李日盛

架构

16张图带你彻底搞懂基数排序

Java架构师迁哥

大招落地:MySQL 插入更新死锁源码分析

AI乔治

Java MySQL 编程 架构

fastJson与一起堆内存溢出'血案'

AI乔治

Java 架构 JVM Fastjson 内存溢出

Flutter 开发从 0 到 1(二)框架与网络

吴小龙同学

flutter ios android 跨平台

上海与鲲鹏的数字共鸣

脑极体

线上排障技巧 | 动态修改LOGGER级别

AI乔治

Java 编程 架构 JVM

架构师训练营 - 第四周课后练习

joshuamai

面试大厂被面试官用MyBatis怼到“哑口无言”?这份MyBatis源码笔记助你吊打面试官!

Java成神之路

Java 程序员 架构 面试 编程语言

面试阿里回来想和Java程序员谈一谈

Java成神之路

Java 程序员 架构 面试 编程语言

Scala基础-语法特性(一):类型和变量

大规模数据处理学习者

scala

架构师训练营第 1 期 - 第 8 周课后练习

Anyou Liu

极客大学架构师训练营

java是如何调用native方法?hotspot源码分析必会技能

诸葛小猿

Java jdk JVM jni hotspot

架构师训练营第1期 - week08 - 作业

lucian

极客大学架构师训练营

杂谈

落曦

C# 7.1先睹为快(第二部分)-InfoQ