最近有几个关于将 ValueType 装箱为对象的问题,特别是它是否发生在某些情况下。
我意识到我不知道的是,“装箱”一个 ValueType(将其视为引用对象)与简单地通过引用访问它之间有什么区别,例如使用 ref 或 out 关键字(您传递的内容只是“指针”)?在这两种情况下,值都在您可以指向它的某个地方(对于 Object 它是堆,对于本地范围的 ValueType,它是......究竟在哪里?)。
如果我不得不猜测,根据我对 C++ 的了解,我会说它是这样工作的:通过引用访问的 ValueType(假设通过参数关键字)保留在其作用域的调用堆栈级别,但是“指向该变量在堆栈中的存储桶的“快捷方式”指针被创建并成为堆栈下一层的一部分。因为该值已经存储在内存中(甚至可能是 CPU 缓存),所以您不必在堆上实例化新的东西;唯一的新东西是指针,它是它自己的 ValueType(一个 IntPtr)并且它本身存储在堆栈中,因此 AFAIK 比将某些东西放入堆中要快。
这是正在发生的事情,还是有其他事情正在发生?
编辑:更清晰:
public void TakesAnObject(Object obj) {...}
public void TakesAnIntValueType(ref int myValue) {...}
public void AnotherIntParameterMethod(out int myValue) {...}
...
//this locally-scoped variable is simply created on the stack.
int myInt = 5;
//Performs boxing; an Object is instantiated in the heap that holds the
//variable value from the stack, and that is passed by ref.
TakesAnObject(myInt);
//Apparently does NOT perform boxing, but we're still dealing with a reference.
//So what's going on?
TakesAnIntValueType(myInt);
//Again created on the stack, with the default 0.
int anotherInt;
//Again, apparently no boxing, but we're dealing with a reference to anotherInt.
AnotherIntParameterMethod(anotherInt);
最佳答案
类引用可以自由复制,并且可以无限期存在。人们可以将它们视为对象的标识符,这些对象(始终)作为独立项目存储在堆上。为了避免过度使用术语“引用”,我喜欢将它们视为 ObjectID。
当例程通过引用接受参数时,该引用是一种特殊类型的东西,它在普通类系统之外(我将其称为 ParameterReference)。与可以无限期存在的 ObjectID 不同,ParameterReference 只允许在被调用函数的持续时间内存在。此外,与始终保存对独立对象的引用的 ObjectID 不同,ParameterReference 保存对堆栈上的局部变量、类 Object 中的字段、数组中的项或自身具有的结构中的字段的引用。匹配这些描述之一。如果 ParameterReference 指向一个局部变量,一旦它超出范围,该变量将不复存在;在此之后尝试使用 ParameterReference 可能会导致数据损坏。然而,由于变量的范围至少会扩展到被调用的例程退出,并且因为那时 ParameterReference 将不复存在,所以 ParameterReference 访问不再存在的变量是没有危险的。
关于.net - Boxing vs ValueType 引用;有什么不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4807659/