NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

.NET 或将引入类型类和扩展

  • 2017-04-17
  • 本文字数:1919 字

    阅读完需:约 6 分钟

类型类是另外一项正被考虑引入.NET 未来版本的特性。在提案“外观和扩展( Shapes and Extensions )”中,该特性被称为外观,它们将大幅提升.NET 泛型的能力。Mads Torgersen 这样描述类型类:

接口抽象的是作为类型实例的对象和值的“外观(shape)”。从根本上讲,类型类背后的思想是抽象类型本身的外观。而且,当通过类型声明引入需要的类型实现一个接口时,其他人可以在单独的代码中实现类型类。

类型类解决了一个长期存在的接口问题:它们无法处理静态函数或操作符重载。这导致了一些问题,比如,在数学库中,对于不同的数值数据类型,需要反复声明相同的函数。

Mads 总结道:

一般来说,外观的声明和接口声明非常像,但它:

几乎可以定义任意类型的成员(包括静态成员)

可以通过扩展实现

可以在特定的地方像类型一样使用

最后一个限制很重要:外观不是类型。外观的主要目的是作为泛型的一种约束,限定类型参数,保证它们有正确的外观,并允许泛型声明体使用那个外观。

与外观的思想紧密相关的是一种经过改进的扩展语法。扩展结构几乎可以为类型类提供任何东西,而不只是方法扩展。考虑下面这个最简单的例子:

复制代码
public shape SNumber<T>
{
static T operator +(T t1, T t2);
static T operator -(T t1, T t2);
static T Zero { get; }
}

Int32 类型已经提供了大部分内容,但它缺少 zero 属性。扩展可以修复这个问题:

复制代码
public extension IntGroup of int : SNumber<int>
{
public static int Zero => 0;
}

然后,你可以像下面这样使用它:

复制代码
public static AddAll<T>(T[] ts) where T : SNumber<T> // shape 用作约束
{
var result = T.Zero; // 使用 shape 的 Zero 属性
foreach (var t in ts) { result += t; } // 使用 shape 的 + 操作符
return result;
}

实现

这实现起来需要一些接口和结构方面的技巧。

  • Shapes 被翻译成了接口,每个成员(甚至是静态成员)都转换成了接口中的实例成员;
  • 扩展被翻译成了结构,每个成员(甚至是静态成员)转换成了结构中的实例成员;
  • 如果扩展实现了一个或多个弯管,则底层的结构实现了那些外观的底层接口。

通常,上述结构被称为“见证结构(witness struct)”。它的存在可以证明一个类遵循外观的规则。或者换句话说,该类在类型类中。

编译器会将上述 AddAll 方法翻译成如下代码:

复制代码
public static T AddAll<T, Impl>(T[] ts) where Impl : struct, SNumber<T>
{
var impl = new Impl();
var result = impl.Zero;
foreach (var t in ts) { result = impl.op_Addition(result, t); }
return result;
}

然后,上述见证结构就可以用于向 AddAll 方法提供必要的功能。结构可以直接在类型上调用方法或者根据需要使用扩展结构。

在类和接口中实现外观

使用和我们扩展基类及实现接口一样的语法,类可以显式实现一个外观。然后,编译器会提供相应的见证结构。

也可以将接口标记为满足外观的要求。下面是一个例子:

复制代码
public extension Comparable<T> of IComparable<T> : SComparable<T> ;

由于 IComparable 和理论上的类型类之间存在一对一关系,所以我们不需要为扩展结构提供扩展体。

泛型类型

事实证明,泛型类型有他们自己的问题。和泛型方法一样,向泛型类添加外观或者类型类作为类型约束需要额外提供一个类型参数。在泛型类上,由于类型参数的数量是其名称的一部分,所以这会导致它和其它名称相同的泛型类型发生冲突。

扩展外观

扩展结构不仅可以用于实现外观,还可以扩展它们。因此,你可以向现有的外观中添加新方法、静态方法及操作符。正如扩展方法一样,语法是一样的,就像它们在底层类型上直接定义了一样。

评论

总的来说,人们对于该特性的反应不错。不过,也有一些修改请求。例如,外观目前必须显式实现。有些开发人员希望,如果特定的类或接口不需要额外扩展方法时,就由编译器隐式实现。Mads 列举了这样做的一些问题:

那可能会导致,为了见证以相同的方式应用到同一类型的同一个外观而生成许多结构类型,有生成的类型过度扩散的风险。如果编译器比较聪明,每个程序集只生成一个,或许可以缓解这种情况,但我们从匿名类型了解到,这种重复数据删除技术非常困难,而且很容易出错。

如果我们允许泛型类型拥有外观约束的类型参数,那么同一个东西拥有多个见证结构会导致实例化的泛型类型具有不同的类型标识,无法互换。

人们还担心外观和扩展绑定得太紧。他们认为,那将来可能会引起混淆。

对此,Mads 答复说:

合并:在我的提案里,“扩展”实际上合并了多个问题:

[……]

我觉得,对于上述服务于所有这些目的的语言机制,有太多内容需要讨论——但归根结底,它们的关系非常密切。如果有一个提案可以将它们清晰地分开,那将是非常有意义的。那也许会更加简单有效。

查看英文原文:.NET Futures: Type Classes and Extensions

2017-04-17 19:001881
用户头像

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

关注

评论

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

【笔记】学《郭东白的架构课》:04|法则二:架构师为什么要学习马斯洛的需求理论?

术子米德

架构师成长笔记

【笔记】学《郭东白的架构课》:02|法则一:为什么有些架构活动会没有正确的目标?

术子米德

架构师成长笔记

模块一第2课随堂练习

苍狼

模块一

Flutter 中使用Chip 小部件【Flutter专题66】

坚果

flutter 1月月更

kafka 原理深度剖析系列|分区分配策略

云智慧AIOps社区

Java kafka 架构 中间件 消息队列

kafka 原理深度剖析系列|调优策略

云智慧AIOps社区

Java kafka 架构 消息队列 消息中间件

深入理解 Go 语言的 map 实现原理

宇宙之一粟

Go map Go 语言 1月月更

开发人员的编程心理学

码语者

编程 心理学 开发

龙蜥社区理事长展望操作系统 2022:加速驶向快车道,云、XPU和开源成“催化剂”

OpenAnolis小助手

Linux 开源 操作系统 国产化 龙蜥

【笔记】学《郭东白的架构课》:03|法则一:如何找到唯一正确的架构目标?

术子米德

架构师成长笔记

【笔记】学《郭东白的架构课》:01|模块导学:是什么在影响架构活动的成败?

术子米德

架构师成长笔记

模块六作业

whoami

「架构实战营」

模块一第1课随堂测验

苍狼

模块一

2022最受Flutter 开发者喜爱的库

坚果

flutter 1月月更

大厂面试:一个四年多经验程序员的BAT面经(字节、阿里、腾讯)

鄙人薛某

字节跳动 java面试 大厂面试 社招 面经分享

HUAWEI DevEco Studio使用技巧【鸿蒙开发 06】

坚果

1月月更

kafka原理深度剖析系列|基本原理与架构

云智慧AIOps社区

Java kafka 架构 消息队列 消息中间件

最好用的 7 款 Vue admin 后台管理系统测评

蒋川

Vue Vue 3 vue admin

使用CodeMirror打造数据科学家使用的IDE(一)

Baihai IDP

人工智能 ide 数据科学 CodeMirror

【笔记】学《郭东白的架构课》:05|法则二:研发人员的人性需求是如何影响架构成败的?

术子米德

架构师成长笔记

带薪撸猫是一种什么样的体验?

万事ONES

微信业务架构图&学生管理系统架构设计

张逃逃

「架构实战营」

2022 年前端工程师进阶必知必会

开源之巅

Serverless

基于Javaweb,Mysql生物信息数据管理系统

叫练

vivo数据库与存储平台的建设和探索

vivo互联网技术

数据库 存储技术 平台架构

极简实现 TiDB 冷热数据分层存储 | He3 团队访谈

PingCAP

顶级好用的 5 款 Vue table 表格组件测评与推荐

蒋川

Vue vue table

基于Javaweb,SSM火车订票系统

叫练

914. 卡牌分组——欧几里得算法

CRMEB

如何用建木CI创建SSL证书并部署到nginx

Jianmu

持续集成 SSL证书 自动化运维

我为InfoQ编辑器提意见

坚果

1月月更

.NET或将引入类型类和扩展_.NET_Jonathan Allen_InfoQ精选文章