写点什么

未来的 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:004900
用户头像

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

关注

评论

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

人工智能 | 打造领域专属的大语言模型

测试人

软件测试

大促高并发系统性能优化实战--京东联盟广告推荐系统

京东科技开发者

再升级!MoneyPrinterPlus集成GPT_SoVITS

程序那些事

工具 AIGC

mac触摸板增强工具BetterTouchTool下载 附BetterTouchTool注册码

Rose

好用的 NTFS 磁盘管理器NTFS Disk by Omi NTFS for mac

Rose

苹果apple音乐制作软件:Logic Pro X for Mac v10.8.1中文版

Rose

当系统闹脾气:用「因果推断」哄稳技术的心

京东科技开发者

「重构:改善既有代码的设计」实战篇

京东科技开发者

万界星空科技AI低代码MES,引领制造业智能化新潮流

万界星空科技

低代码 低代码平台 mes 万界星空科技 低代码云MES

传智教育引通义灵码进课堂,为技术人才教育学习提效

阿里巴巴云原生

阿里云 云原生 通义灵码

传智教育引通义灵码进课堂,为技术人才教育学习提效

阿里云云效

阿里云 云原生 通义灵码

打造领域专属的大语言模型

霍格沃兹测试开发学社

Wi-Fi 7 Technology IPQ5332 vs. IPQ9574: Comparison of Core Chips for Industrial Routers

wifi6-yiyi

WiFi7 ipq9574

Go语言中使用 sqlx 来操作 MySQL

左诗右码

Go 语言

万界星空科技服装行业MES系统解决方案

万界星空科技

工业互联网 制造业 服装行业 mes 万界星空科技

高效的AirPods耳机管理工具 AirBuddy for Mac v2.6.3汉化版

Rose

按图搜索的精准营销:基于拍立淘API返回值的用户画像

技术冰糖葫芦

API Explorer API 接口 API 测试 API】

The Difference Between Router Mode and Bridge Mode

wallyslilly

ETL数据集成丨将SQL Server数据同步至Oracle的具体实现

RestCloud

数据库 oracle ETL 数据集成 SQL Server

提升团队效率:最佳文件管理软件7选

爱吃小舅的鱼

文件管理 文件管理软件

淘宝商品评论接口API:获取淘宝商品评论数据评论总数(支持排序)

tbapi

淘宝API接口 淘宝商品评论接口 淘宝商品评论数据 淘宝商品评论API

变“金点子”为“好应用”,合合信息智能文档处理技术助力大学生探索AI创新边界

合合技术团队

人工智能 科技 比赛 合合信息

KubeCon China 2024 | KubeEdge 邀您共话边云协同AI智算

华为云原生团队

云计算 容器 云原生

智能搜索,Paste for Mac让你快速找到需要的剪切板内容!

Rose

Clicker for YouTube mac版 YouTube视频播放器客户端

Rose

Charles for Mac注册激活版:轻松地捕获分析修改HTTP、HTTPS和TCP流量

Rose

哪里有Photoshop 2024激活补丁?PS2024中文破解资源分享【mac&win】

理理

科大讯飞p30和c10s、c10区别 选哪个好

妙龙

科大讯飞 学习机

周期补数据、定时补数据,深入了解两种补数据的特殊方式

袋鼠云数栈

大数据

面试官:说说volatile应用和实现原理?

王磊

SwitchResX for Mac 轻松调整苹果电脑显示器配置参数

Rose

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