使用ref关键字传递值

5
阅读完关于ref关键字的MSDN文章后,我对于在C#中使用ref关键字传递值类型时会发生什么感到困惑。文档说明ValueTypes不会被装箱。我的问题是,C#如何处理将值类型作为引用传递?它是否传递了一些在栈上分配的数据的副本?谢谢。

5
即使是引用类型,它们也不是按引用传递,而是通过值传递它们的地址。请参阅 Jon Skeet 的《C# 参数传递》(http://www.yoda.arachsys.com/csharp/parameters.html)。 - Habib
2个回答

8
它是否将一些副本传递到分配在堆栈上的数据中?
不,它不会复制。ref和out关键字可与C中的指针传递或C++中的引用传递进行比较,当变量的内存位置(即地址)传递到目标方法时,该方法将使用传递的内存位置直接原地修改该值。
知道变量是按引用传递的,编译器插入指令以将ref变量视为地址,从而允许就地修改。

0

简而言之:装箱不是“如何创建引用”,而是“如何为那些不期望该确切类型的消费者打包原始值类型”。

在.NET中,引用类型是堆上的类实例。像intdouble这样的值类型只是字节:32位int只是四个字节的零和一。当你把它放在一个System.List(老式的泛型前)中,然后再取出来时,如果你调用GetType(),编译器怎么知道该做什么?它只有四个字节的……什么?谁知道呢?如果它在List中存储了一个指针,它将有一个指向四个字节的……谁知道呢?

在你自己的方法中,生成的代码知道你的变量是什么。常规的强类型检查。但是当你把变量的值发送给只知道他正在等待Object的其他人时,这种方法就行不通了。

因此,当您将int添加到List中或将其传递给以Object作为参数的函数时,编译器必须向其中添加一些信息,以便其他人知道他正在得到什么。

因此,“装箱”意味着将非引用值打包成一个可以被视为Object实例的对象。对于普通的ref参数,这是不必要的,因为整个过程中类型都是已知的:函数内部生成的代码不必准备处理任何任意的引用类型。它知道它正在获取(例如)指向整数的指针,这就是它将要获得的全部内容。装箱提供了在这种情况下不需要的功能,因此编译器不会浪费用户的周期。

装箱(boxing)不是唯一的方法,可以以最广义的意义引用例如 double。相反,装箱是将 double 视为可以存储在 System.List 中的对象的唯一方法:它必须位于堆上,可以转换为 Object,必须具有运行时类型信息等等。

对于以下内容,调用者或被调用者只需要某个地方的 64个零和一的地址

void f(ref double d) { d *= 2; }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接