题
在c#中,doe坐着是什么意思:“盒子和unox”?
在这里,我从MSDN提取了文本。
但是这种便利是有代价的。将添加到ArrayList的任何参考或值类型都隐含地升至对象。如果这些项目是价值类型,则将它们添加到列表中时必须装箱,并在检索时将其取消装箱。铸件和拳击和拆箱操作都降低了性能;在您必须在大型收藏中迭代的情况下,拳击和拆箱的效果可能非常重要。
谢谢!
解决方案
这是一个更详细的解释,着眼于通用语言运行时的内部。
首先,让我们在 价值类型 和 参考类型:
- 价值类型在 堆 并将其副本传递给了称为方法
- 在 托管堆 堆栈仅保留其位置的指针(引用)。位置而非对象传递给称为方法
如果您不知道堆栈是什么(不要冒犯),则是一个存储区域,在方法和呼叫者功能的地址中保存本地变量 return
指示(只是简要介绍并提供一般答案)。当您调用方法时,堆栈上的足够区域是 静态 分配给它,因此堆栈分配始终称为静态分配。
相反,堆是一个与堆栈分离的内存区域, 财产 在运行过程中,必须首先向操作系统索取分配的过程,这就是为什么称为 动态分配 (例如,如果您不在IF语句中运行,则可能不会为您的过程分配内存,而是总是分配堆栈)。
只是为了在堆和堆栈上做出最后一个示例:在诸如C ++之类的语言中,声明 int[100] a;
静态分配100*8字节在堆栈上(假定64位系统),而 int* a = new int[100];
在堆栈上宣布一个8个字节(在64位系统上)区域,并在堆上要求更多的字节(如果和地方)。
现在让我们谈谈C#:
拳击
由于int是一种值类型,并且在堆栈上分配了int,当您将其投射到对象或任何其他参考类型时(实际上没有其他参考类型,int可以继承,但这是一般规则)必须必须变为参考类型。因此,分配了堆上的新区域,对象是 盒子 它的内部和堆栈将其指向它。
拆箱
恰恰相反:当您有一个参考类型(例如对象),并希望将其施放为一个值类型,例如int,必须将新值保存在堆栈上,因此CLR变为堆, 未盒子 值并将其复制到堆栈中。
换句话说
记住 int[]
和 int*
例子?简而言之 int
在C#中,运行时期望其堆栈位置为 保持价值 但是当你有 object
, ,它预计其真正的价值将位于堆栈指向的堆位置。
其他提示
.NET框架中有两种不同类型。
估算型例如int,double,单身
参考型ArrayList列表,还有更多
类型的变量 估算型 存储在堆栈中引用分型 变量存储在堆中
类型的变量 估算型 存储值引用分型 变量存储对值的引用
因此,如果您复制 值类型 变量 - 有一个 真实的副本 一个值,但如果您复制一个 引用类型 可变 - 您将得到一个 附加参考 到同一变量。
您的问题中的拳击意味着,将处理一个valueType变量(例如int),被认为是参考类型变量 - .NET将其带入新的 盒子. 。因此,它将被封装在堆中,并将有参考。
如果您希望该值再次在ValueType变量中再次出现 Unbox 它(将其从开箱即用)。因此,该值将被从堆中取出 - 并再次存储/给出堆栈。
ArrayList仅存储对象。用于参考类型(喜欢 String
)这没问题,但是对于valueType(int,dateTime,..)是。
在将它们存储为普通对象之前,需要将这些估算型转换为对象。这种“转换为对象”称为“拳击”,需要一点时间。
当您读回值时,您需要从对象转换为 int
(或者是什么)。这称为“拆箱”。