0

0

C# ref readonly参数方法 C#如何传递大的struct而无需拷贝

幻夢星雲

幻夢星雲

发布时间:2026-02-02 09:43:13

|

583人浏览过

|

来源于php中文网

原创

能,ref readonly参数可避免struct拷贝,但仅限传入可寻址左值且方法内不修改时;传右值会编译报错,in参数语义等价但更简洁安全。

c# ref readonly参数方法 c#如何传递大的struct而无需拷贝

ref readonly参数能避免struct拷贝吗

能,但仅限于方法体内不修改该参数的前提下。C# 7.2 引入的 ref readonly 允许你以只读引用方式传递 struct,彻底跳过值类型的默认按值复制行为——前提是调用方传入的是可寻址的左值(比如局部变量、数组元素、字段),而非临时对象(如字面量或 new 表达式结果)。

常见误区:以为加了 ref readonly 就“一定不拷贝”。其实如果传入的是不可寻址的右值(例如 SomeMethod(ref readonly new BigStruct())),编译器会报错 CS8337: Cannot use a result of 'new BigStruct()' as a ref or out value because it is not a variable,根本过不了编译。

什么时候必须用ref readonly而不是ref

当你需要高性能访问大型 struct(比如含多个 double 字段的几何类型、固定大小缓冲区等),又**明确禁止方法内部修改其状态**时,ref readonly 是唯一兼顾安全与零拷贝的选择。

ref 虽然也避免拷贝,但开放了写权限,容易破坏封装或引发意外副作用;而 readonly 修饰后,编译器会在方法体内对所有成员访问做只读检查:

  • 不能给字段赋值(param.x = 1;编译错误
  • 不能调用非 readonly 成员方法(哪怕该方法逻辑上不修改状态)
  • 可以安全地读取字段、调用 readonly 方法、访问属性(只要 getter 是 readonly

示例:

struct Matrix4x4
{
    public double M11, M12, M13, M14;
    // ... 16个double,约128字节
    public readonly double Determinant => /* 计算逻辑 */;
}

void ProcessMatrix(ref readonly Matrix4x4 m) { Console.WriteLine(m.Determinant); // ✅ OK // m.M11 = 0; // ❌ 编译错误 // m.ToString(); // ❌ 若ToString()不是readonly方法 }

ref readonly参数的调用限制和陷阱

它对调用端有严格要求,稍不注意就触发编译错误或隐式拷贝:

谱乐AI
谱乐AI

谱乐AI,集成 Suno、Udio 等顶尖AI音乐模型的一站式AI音乐生成平台。

下载
  • 只能传入变量、字段、数组索引等“可寻址位置”,不能传表达式结果(ProcessMatrix(ref readonly GetMatrix()) ❌)
  • 不能用于 async 方法参数(因为 await 可能导致帧移动,引用失效)
  • 不能作为 outref 参数重载的区分依据(void M(ref T)void M(ref readonly T) 不能共存)
  • 若 struct 含引用类型字段(如 string),ref readonly 只保证 struct 本身地址不变、字段不可改,但不阻止通过引用字段间接修改堆对象

性能提示:对于小于 16 字节的小 struct(如 Point, Guid),按值传递反而可能更快——CPU 寄存器能直接承载,避免取地址和解引用开销。

替代方案对比:Span 和 in 参数

C# 7.2 同时引入了 in 参数关键字,语义上等价于 ref readonly,但更简洁且意图更明确:

  • void M(in Matrix4x4 m) 等价于 void M(ref readonly Matrix4x4 m)
  • in 更推荐用于只读输入场景,编译器对其做了额外优化(如允许传入只读临时变量,某些情况下放宽右值限制)
  • 若需切片或遍历 struct 的原始字节(比如序列化),Span 配合 MemoryMarshal.AsBytes 更底层可控,但需 unsafeSystem.Runtime.CompilerServices.Unsafe

真正复杂的地方在于:是否值得为避免一次拷贝,增加调用约束、破坏 API 易用性?尤其当 struct 生命周期短、调用频次低时,in 带来的收益可能被可维护性成本抵消。实际压测比理论推导更可靠。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

523

2023.08.02

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

133

2025.08.29

C++中int、float和double的区别
C++中int、float和double的区别

本专题整合了c++中int和double的区别,阅读专题下面的文章了解更多详细内容。

103

2025.10.23

javascriptvoid(o)怎么解决
javascriptvoid(o)怎么解决

javascriptvoid(o)的解决办法:1、检查语法错误;2、确保正确的执行环境;3、检查其他代码的冲突;4、使用事件委托;5、使用其他绑定方式;6、检查外部资源等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

177

2023.11.23

java中void的含义
java中void的含义

本专题整合了Java中void的相关内容,阅读专题下面的文章了解更多详细内容。

102

2025.11.27

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

399

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

576

2023.08.10

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

399

2023.07.18

go语言 注释编码
go语言 注释编码

本专题整合了go语言注释、注释规范等等内容,阅读专题下面的文章了解更多详细内容。

60

2026.01.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
CSS3 教程
CSS3 教程

共18课时 | 5.1万人学习

Sass 教程
Sass 教程

共14课时 | 0.8万人学习

Pandas 教程
Pandas 教程

共15课时 | 1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号