【问题标题】:Box and UnBox what does it means? [duplicate]Box和UnBox是什么意思? [复制]
【发布时间】:2011-01-25 14:33:59
【问题描述】:

可能的重复:
Why do we need boxing and unboxing in C#?
What is boxing and unboxing and what are the trade offs?

在 C# 中,sit 是什么意思:“Box and UnBox”?

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

但这种便利是有代价的。 任何引用或值类型 添加到 ArrayList 是隐式的 向上转换为对象。如果物品是 值类型,它们必须装箱时 它们被添加到列表中,并且 取回时拆箱。两个都 铸造和拳击和 拆箱操作减少 表现;拳击的效果和 拆箱可能非常重要 必须迭代的场景 大量收藏。

谢谢!

【问题讨论】:

标签: c# .net boxing unboxing


【解决方案1】:

这里有一个更详细的解释,着眼于公共语言运行时的内部。

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

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

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

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

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

现在让我们谈谈 C#:

拳击

由于 int 是一种值类型,并且是在堆栈上分配的,所以当您将其强制转换为 object 或任何其他引用类型(实际上没有其他引用类型可以从 int 继承,但这是一般规则)时,值必须成为一个引用类型。因此在堆上分配了一个新区域,对象被装箱在其中,堆栈中保存着一个指向它的指针。

拆箱

正好相反:当你有一个引用类型,比如object,并且想把它转换成一个值类型,比如转换成int,新的值必须保存在栈上,所以CLR去堆,un-boxes 值并将其复制到堆栈中。

换句话说

还记得int[]int* 的例子吗?简单地说,当您在 C# 中有 int 时,运行时期望它的堆栈位置保存值,但是当您有 object 时,它希望它的实际值位于由堆栈。

【讨论】:

  • 结构(值)类型的存储位置(参数、变量或字段)将其所有数据保存在存储位置本身的字段中。自动变量和参数一般保存在栈上;类字段始终保存在堆上;结构字段保存在包含它们的结构中。相比之下,引用类型的存储位置中唯一保存的东西要么是对实际保存数据的堆对象的引用,要么是空引用。
  • 关于boxing 过程的一个重要说明:当它发生时,值的副本实际上是在传递而不是值本身,当你调用一个接受@ 的方法时,这有点相似987654329@作为参数。
【解决方案2】:

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

值类型 比如int、double、single

参考类型 数组列表 列表 还有很多很多

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

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

所以如果你复制一个 ValueType 变量 - 会有一个值的真实副本 但如果您复制一个 ReferenceType 变量 - 您将获得一个对 SAME 变量的附加引用

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

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

【讨论】:

  • "ValueTypes 类型的变量存储在堆栈中" 不,通常不会。它们通常存储在引用类型的对象中,位于堆上。
  • @BenVoigt 根据Eric Lippert's Blog "在桌面 CLR 上的 C# 的 Microsoft 实现中,当值是非封闭的局部变量或临时变量时,值类型存储在堆栈中lambda或匿名方法的局部变量,并且方法体不是迭代器块,并且抖动选择不注册值” - 所以我认为我的回答应该可以接受
  • 你的回答做出了一个普遍的陈述,关于一些甚至不接近普遍的东西。
  • msdn.microsoft.com/en-us/library/yz2be5wk.aspx 当 CLR 将值类型装箱时,它会将值包装在 System.Object 中并将其存储在托管堆中。
【解决方案3】:

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

这些值类型需要先转换为对象,然后才能将它们存储为普通对象。这种“转换为对象”称为“装箱”,需要一点时间。

当您读回该值时,您需要将 Object 转换为 int(或其他任何值)。这称为“拆箱”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-12
    • 2015-01-22
    • 2020-10-27
    • 2015-07-15
    • 2018-07-17
    • 2012-08-13
    • 2011-12-23
    • 2013-10-27
    相关资源
    最近更新 更多