写点什么

未来的 C#之只读引用与结构体

  • 2017-04-27
  • 本文字数:1812 字

    阅读完需:约 6 分钟

C++ 中提供了 const 特性,使用该特性定义的参数,其所引用的参数或对象将不会被调用函数修改(当然 const 还提供了更多的特性,参见“ Const 正确性”)。在新的建议中,C#也将提供类似的特性。

只读 ref 参数

在 C#中,“只读引用”也可称为“in 参数”,两者提供了类似的限制。只读引用的基本思想是,如果用“readonly ref”或仅是“in”标注一个参数,那么编译器会解释为“将该参数按引用传递以改进性能,但不允许实际更改该参数”。该特性对于在高性能场景下的大型结构体尤为有用。在建议中引用了如下的例子:

我们知道,在 XNA 等图形库中的向量 / 矩阵数学运算符是具有 ref 操作符的,这纯粹是出于性能上的考虑。Roslyn 编译器本身就有代码使用了结构体,以避免内存分配,并可通过引用的方式传递结构体,免除复制的繁琐。

该语法还结合了 C++ 版本的 const。即参数本身是不可更改的,参数所引用的对象或结构体中的所有数据也是不可更改的。

当前在通过引用传递一个参数时,必须使用“ref”或“out”关键字。在这个建议实现后,使用“in”参数无需受此限制。进而表达式的结果也可以传递进来(当前这在 VB 中是允许的,但是在 C#中尚不允许)。

实现细节

对比“ref”和“out”参数,它们的重载规则具有相同的工作机制。

这依然有待议定,但是当前的计划是不允许“in”参数被匿名函数或 async 函数捕获(即生成一个闭包对象)。捕获“in”参数的问题在于会导致一次拷贝,这破坏了使用“in”参数的初衷,即避免拷贝所导致的性能损耗。

将参数标为“readonly ref”或“in”,并不会令引用值成为不可变值。虽然参数值无法被声明函数更改,但可以在其它地方修改。无需使用多线程,只需能访问参数所引用原始变量的方法即可。

在结构体上调用方法可能会导致问题。在建议中是这样说的:

结构体的所有常规实例方法可转变(mutate)实例,或是对实例暴露引用(ref-expose),因此必须要创建一个临时拷贝,正如当前对接收者是只读域时的做法。

但是,由于没有考虑向后兼容,也不存在变通方案,所以编译器只是给出一个警告,以确保用户留意到这一隐式拷贝。

使用“out”参数时,一个特殊的参数标识了是否需要“in”参数。该参数将被旧的编译器忽略,因此没有向后兼容的问题。

只读 ref 返回

与该特性密切相关的是将 ref returns 标为只读的功能。开发人员使用“in”参数,主要因为它能提供良好的性能,但是“in”参数不允许返回表达式的结果。返回值必须是正常 ref 返回的一个合法变量,其中可以包含数组元素、ref 参数和对象中的域。

ref/in 的扩展方法

“ref”扩展方法将允许扩展方法修改传递进来的结构体。需要编译器能验证传递给 ref 扩展方法的参数是可变的。

虽然“in”扩展方法不允许修改参数,但对于性能敏感的代码依然十分有用,尤其是结构体非常大的时候。这时当然不需要一个可变参数。

在上面两种情况下,该特性只能用于结构体。

编辑按:假定广泛使用了 PureAttribute ,编译器将不允许对“in”扩展方法调用非 PureAttribute 的方法。但由于对性能并无太大改善,因此不大可能广泛应用。

只读结构体

将结构体变量标为 readonly 可能会对性能产生影响。编译器无法确定某个调用是否会对结构体产生改动,因此会默认能够修改,并始终复制只读结构体变量的副本。

使用该特性,开发人员可以在类型层面上将整个结构体标为只读。这样一来,编译器就知道:在通过只读结构体的变量暴露该只读结构体时,不需要进行拷贝。

在建议中指出:

唯一一个显而易见的问题在于:是否需要将其中一些方法改为赋值(mutator)方法。

目前,对只读结构体进行逐个控制只会增加不必要的复杂性,我们可以后期需要时再行添加。

当前,我们假定可变和不可变成员“混合”的结构体并不常见。此外,可变结构体的部分变量通常需要是 LValues,从而避免隐式拷贝的影响。

缺点

建议还指出,这些功能对已有代码不大可能有帮助,但在如下新场景中会很有用,例如:

  • 在计算能力关乎费用,响应能力关乎竞争优势的云场景或数据中心场景下。
  • 对延迟有软性实时需求的游戏 /VR/AR 场景。

在建议中也提出了警告,在“in”参数上的限制可循环作用于被调用函数。但这一问题并不严重,因为已经可以使用“out”参数执行同一操作了。

查看英文原文: C# Futures: Read-Only References and Structs


感谢孙薇对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2017-04-27 19:005357
用户头像

发布了 227 篇内容, 共 85.5 次阅读, 收获喜欢 28 次。

关注

评论

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

假如问:你是怎样优化Vue项目的,该怎么回答

bb_xiaxia1998

Vue

腾讯前端二面高频手写面试题总结

helloworld1024fd

JavaScript

明天 9 点!Doris Summit 2022 拉开序幕,立即报名年度技术盛会!

SelectDB

数据湖 云原生 实时数仓 湖仓一体 数据库·

js函数柯里化-面试手写版

helloworld1024fd

JavaScript

双机热备的优点简单分析-行云管家

行云管家

高可用 双机热备

程序员面试中一面、二面、三面有什么区别?

小小怪下士

Java 程序员 java面试

2022年是最烂的一年吗?我的2022年终总结

Zhendong

总结 年终总结 2022年终总结

JS继承有哪些,你能否手写其中一两种呢?

helloworld1024fd

JavaScript

前端二面手写面试题总结

helloworld1024fd

JavaScript

ChatGPT的一小步,NLP范式转变的一大步

OneFlow

人工智能 深度学习

喜报!SelectDB 携手中航信移动科技有限公司、四川大数据技术服务中心,双双入选大数据“星河(Galaxy)”优秀案例

SelectDB

数据库 大数据 数据湖 云原生 云上架构

一文详解RocketMQ的存储模型

华为云开发者联盟

开发 华为云 企业号 1 月 PK 榜

技术管理 之 跨功能需求管理

码猿外

技术管理 非功能性需求 跨功能性需求

Serverless时代的微服务开发指南:华为云提出七大实践新标准

华为云开发者联盟

微服务 云原生 后端 华为云 企业号 1 月 PK 榜

校招前端一面必会vue面试题指南

bb_xiaxia1998

Vue

海量数据同步首选 SeaTunnel Zeta 引擎正式发布!

Apache SeaTunnel

大数据 开源 apache 社区 Apache SeaTunnel 数据集成平台

OneFlow源码解析:静态图与运行时

OneFlow

人工智能 深度学习

极狐GitLab与欧拉操作系统完成兼容认证,开源产业自主创新再突破!

openEuler

Linux 开源 操作系统 openEuler 资讯

TiDB 6.5 LTS 发布 企业级关键能力跃升

极客天地

云原生安全系列 4:6个 Kubernetes 安全最佳实践

HummerCloud

Kubernetes 云原生安全

注意这八个容易损坏LED显示屏的情况

Dylan

LED显示屏 全彩LED显示屏 led显示屏厂家

前端高频vue面试题总结

bb_xiaxia1998

Vue

读 NebulaGraph源码 | 查询语句 LOOKUP 的一生

NebulaGraph

图数据库 源码解读

软件测试/测试开发丨iOS 自动化测试踩坑(一): 技术方案、环境配置与落地实践

测试人

ios xcode 软件测试 自动化测试 测试开发

前端一面常考react面试题

beifeng1996

React

一种多维数据库的数据事务专利解读

元年技术洞察

数据中台 数字化转型 专利解析 多维数据库

如何在Java程序中合并和拆分Excel文档

Geek_249eec

Java Excel 工作表

ZooKeeper 避坑实践:SnapCount 设置不合理导致磁盘爆满,服务不可用

阿里巴巴云原生

zookeeper 阿里云 云原生

【双机热备小知识】两台服务器可以做双机热备吗?

行云管家

高可用 双机热备

阿里云前端专家冯军:前端用户体验该如何优化

云布道师

阿里云

未来的C#之只读引用与结构体_.NET_Jonathan Allen_InfoQ精选文章