阅读完关于ref关键字的MSDN文章后,我对于在C#中使用ref关键字传递值类型时会发生什么感到困惑。文档说明ValueTypes不会被装箱。我的问题是,C#如何处理将值类型作为引用传递?它是否传递了一些在栈上分配的数据的副本?谢谢。
简而言之:装箱不是“如何创建引用”,而是“如何为那些不期望该确切类型的消费者打包原始值类型”。
在.NET中,引用类型是堆上的类实例。像int
或double
这样的值类型只是字节: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; }