在阅读the MSDN article on the ref keyword之后,我对使用ref关键字传递值类型时C#的作用感到困惑。文档指出ValueTypes没有装箱。我的问题是C#如何处理传递值类型作为引用?它是否将一些副本传递给堆栈上分配的数据?谢谢。
答案 0 :(得分:8)
是否将一些副本传递给堆栈上分配的数据?
不,它不会复制。当传递内存位置(即地址)时,ref
和out
关键字可以与通过C中的指针传递或通过C ++中的引用传递进行比较目标方法。然后,接受引用的方法将使用传入的内存位置直接修改该值。
知道变量是通过引用传递的,编译器会插入将ref
变量视为地址的指令,允许就地修改。
答案 1 :(得分:0)
tl;博士:拳击不是“你如何创建参考”;它是“如何为不期望精确类型的消费者打包原始值类型”。
在.NET中,引用类型是堆上的类实例。像int
或double
这样的值类型只是字节:32位int只有4个字节的零和1。当你把它放入时,比如说System.List
(Granpaw在General Store中缩减的旧式预先通用类型),然后将其取回,编译器如何知道如果你做什么在上面调用GetType()?它只有四个字节......什么?谁知道?如果它在List
中存储了一个指针,它会有一个指针到四个字节......谁知道?
在您自己的方法中,生成的代码知道您的变量是什么。定期强大的类型检查。但是,当您将变量的值发送给只知道他期望Object
的其他人时,这不起作用。
因此,当您向int
添加List
或将其传递给以Object
作为参数的函数时,编译器必须向其中添加一些信息,以便其他人知道他得到了什么。
所以“Boxing”意味着将非参考值打包到一个可被视为Object
实例的对象中。对于普通的ref
参数,这是不必要的,因为类型是全部已知的:为函数的内容生成的代码不必准备好处理任何任意引用类型。它知道它正在获取(例如)一个指向整数的指针,而这就是它将要获得的全部内容。 Boxing提供了在这种情况下不需要的功能,因此编译器不会浪费用户的周期。
拳击不是唯一的方式,例如,double
有一个参考(在最广泛的意义上)。相反,装箱是将double
视为可以存储在System.List
中的对象的唯一方法:它必须在堆上,它必须可以转换为Object
,必须有运行时类型信息等。
对于以下内容,所有调用者或被调用者需要的是64 zeroes and ones某处的地址:
void f(ref double d) { d *= 2; }