硬核干货——《中小企业 AI 实战指南》免费下载! 了解详情
写点什么

.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:002392
用户头像

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

关注

评论

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

游戏开发巨擘的选择:2023 TGA获奖工作室共同青睐Perforce版本控制

龙智—DevSecOps解决方案

游戏开发 游戏 TGA

关于「日志采样」的一些思考及实践

京东科技开发者

专科学历被裁,我是如何逆天改命的?

霍格沃兹测试开发学社

Atlassian Intelligence功能简介,AI驱动生成、概括、优化内容,助力工作效率加倍

龙智—DevSecOps解决方案

AI Atlassian

Gartner 2023 API管理魔力象限发布,SmartBear被评为“远见者”

龙智—DevSecOps解决方案

Gartner SmartBear

2023年哪个前端框架用的最多?

伤感汤姆布利柏

WebSocket 教程:实现二进制数据传输的详细指南

Apifox

前端 后端 websocket 实时通信 二进制数据

Unity 现正式支持 visionOS 平台,赋能Apple Vision Pro应用创建

财见

新型生成式 AI 助手 Amazon Q(预览版)上线

亚马逊云科技 (Amazon Web Services)

人工智能 生成式人工智能

云MySQL 主节点故障

腾讯云混沌演练平台

混沌工程 MySQL主节点故障

IBM Storage Ceph:现代数据湖仓的理想技术底座

财见

【鸿蒙千帆起】高德地图携手HarmonyOS NEXT,开启智能出行新篇章

HarmonyOS开发者

HarmonyOS

TDengine 签约杭州云润,助力某大型水表企业时序数据处理

TDengine

tdengine 时序数据库

跨语言高性能 RPC 框架 Focus 发布 V1.2.0

dinstone

RPC框架

演讲回顾:如何为大规模研发团队加速CI构建,实现高效流水线

龙智—DevSecOps解决方案

DevSecOps Atlassian

Ray on ACK 实践探索之旅 - RayCluster 篇

阿里巴巴云原生

阿里云 云原生 ray

深入剖析Java中的反射,由浅入深,层层剥离!

不在线第一只蜗牛

Java 编程 前端 开发语言

职场逆袭:被裁成为薪资翻倍的契机

测试人

软件测试

Wireshark中的TCP协议包分析

小齐写代码

重构商业生态:支付宝小程序云与AI融合的无限可能

TRaaS

小程序 支付宝小程序 AI 小程序云

低代码平台如何快速开发应用?

互联网工科生

低代码开发 JNPF

2023 OpenHarmony年度运营报告

OpenHarmony开发者

OpenHarmony

京东广告算法架构体系建设--大规模稀疏场景高性能训练方案演变

京东科技开发者

大前端CPU优化技术--NEON技术

江湖修行

性能优化 大前端 arm架构 异构计算

云服务器是干什么的?其工作原理及优势解析

天翼云开发者社区

云计算 云服务器

云电脑超详细技术讲解

天翼云开发者社区

云计算 云电脑

代码可控是什么意思?有哪些优势?

行云管家

信创 国产化 代码可控

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