Box和UnBox是什么意思?

可能重复:
为什么我们需要在C#中装箱和拆箱?
什么是拳击和拆箱,有什么权衡?

在C#中,doe sit意味着什么:“Box and UnBox”?

这里是我创建Text的MSDN的摘录。

但这种便利需要付出代价。 添加到ArrayList的任何引用或值类型都隐式地向上转换为Object。 如果项目是值类型,则在将它们添加到列表时必须将它们装箱,并在检索它们时取消装箱。 铸造,装箱和拆箱操作都会降低性能; 在必须迭代大型集合的情况下,装箱和拆箱的效果可能非常显着。

谢谢!

这是一个更详细的解释,它关注公共语言运行时的内部。

首先,让我们区分值类型引用类型

  • 值类型保存在堆栈上,并将其副本传递给调用的方法
  • 引用值保存在托管堆中 ,并且堆栈仅包含指向其位置的指针(引用)。 位置而不是对象被传递给被调用的方法

如果您不知道堆栈是什么(不要被冒犯),它是一个存储区域,它在方法中保存局部变量,并使用用于return指令的调用函数的地址(只是简短并提供一般答案)。 当您调用方法时,堆栈上的足够区域将静态分配给它,因此堆栈分配始终称为静态分配。

相反,堆是一个与堆栈分开的内存区域,它是运行进程的属性 ,必须首先向操作系统请求分配,这就是为什么它被称为动态分配 (如果你不在if语句中运行)例如,可能不会为您的进程分配内存,而是始终分配堆栈)。

只是为了在堆和堆栈上做一个最后的例子:在C ++等语言中,声明int[100] a; 静态地在堆栈上分配100 * 8个字节(假定为64位系统),而int* a = new int[100]; 在堆栈上声明一个8字节(在64位系统上)并在堆上请求800多个字节,如果可用的话。

现在让我们谈谈C#:

拳击

由于int是一个值类型,并且在堆栈上分配,当你将它转换为对象或任何其他引用类型时(实际上没有其他引用可以inheritance的引用类型,但它是一般规则),该值必须是必需的参考类型。 因此,堆上的新区域被分配,对象被装入其中,并且堆栈包含指向它的指针。

拆箱

恰恰相反:当你有一个引用类型,比如object,并希望将它转换为一个值类型,比如int,新值必须保存在堆栈上,所以CLR转到堆, 取消框值并将其复制到堆栈。

换一种说法

还记得int[]int*示例吗? 简单地说,当您在C#中使用int时,运行时期望其堆栈位置保持该值,但是当您有object ,它期望其实际值位于堆栈指向的堆位置。

.net Framework中有两种不同的类型。

ValueTypes ,如int,double,single

ReferenceTypes ArrayList List以及许多,更多

ValueTypes类型的变量存储在Stack ReferenceType中,变量存储在堆中

ValueTypes类型的变量存储VALUE ReferenceTyped变量将REFERENCE存储到值

因此,如果复制ValueType变量 – 存在值的实际副本 ,但如果复制ReferenceType变量,则会获得对SAME变量的附加引用

在你的问题中装箱意味着,一个valueType变量(例如int)将像参考类型变量一样处理 – .net将它放入一个新的框中 。 所以它将封装在堆中,并且会有引用。

如果您希望将值再次置于valueType变量中,则必须将其取消装箱 (将其从包装盒中取出)。 因此,该值将从堆中取出 – 并再次存储/提供给堆栈。

ArrayList仅存储对象。 对于引用类型(如String ),这是没有问题的,但对于ValueType(int,DateTime,..),它是。

在将这些值类型存储为普通对象之前,需要将这些值类型转换为对象。 这种“转换为对象”被称为“拳击”,需要一点时间。

当您重新读取值时,需要将Object从Object转换为int (或其他任何内容)。 这称为“拆箱”。