装箱和拆箱

发布于 2024-09-29 07:48:10 字数 585 浏览 0 评论 0原文

可能的重复:
什么是装箱和拆箱以及交易是什么折扣?

好的,我了解装箱和拆箱时会发生什么的基本概念。

Box 将值类型(堆栈对象)扔进 System.Object 并将其存储在堆上 Unbox 会将该对象在堆上保存该值类型的对象解包,并将其扔回到堆栈上,以便可以使用它。

这是我不明白的地方:

  1. 为什么需要这样做...具体的现实世界示例

  2. 为什么泛型这么有效吗?他们说因为泛型不需要拆箱或装箱,好吧..我不明白为什么...泛型背后是什么

  3. 为什么泛型比其他类型更好。例如,我们可以说其他集合吗?

所以总而言之,我不明白这一点在现实世界中的应用程序中的代码,然后进一步了解它如何使泛型更好......为什么在使用泛型时它不需要首先执行任何操作。

Possible Duplicate:
What is boxing and unboxing and what are the trade offs?

Ok I understand the basic concept of what happens when you box and unbox.

Box throws the value type (stack object) into a System.Object and stores it on the heap
Unbox unpackages that object on the heap holding that value type and throws it back on the stack so it can be used.

Here is what I don't understand:

  1. Why would this need to be done...specific real-world examples

  2. Why is generics so efficient? They say because Generics doesn't need to unbox or box, ok..I don't get why...what's behind that in generics

  3. Why is generics better than lets say other types. Lets say for example other collections?

so all in all I don't understand this in application in the real world in terms of code and then going further how it makes generics better...why it doesn't have to do any of this in the first place when using Generics.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

神魇的王 2024-10-06 07:48:11
  1. 每当您想要在 object 变量中保存 int 时,就需要进行装箱。
  2. int 的通用集合包含 int[] 而不是 object[]
  3. int 放入非泛型集合后面的 object[] 需要将 int 装箱。
    int 放入泛型集合后面的 int[] 中不会涉及任何装箱。
  1. Boxing needs to be done whenever you want to hold an int in an object variable.
  2. A generic collection of ints contains an int[] instead of an object[].
  3. Putting an int into the object[] behind a non-generic collection requires you to box the int.
    Putting an int into the int[] behind a generic collection does not invlove any boxing.
ぃ弥猫深巷。 2024-10-06 07:48:11

首先,栈和堆是实现细节。值类型不是通过在堆栈上定义的。毫无疑问,堆栈和堆的概念将用于所有能够托管 CLR 的系统:
链接

除此之外:

当某个值类型被装箱时,会读取该值类型中的数据,创建一个对象,并将数据复制到新对象。
如果您将集合中的所有项目装箱,那么这是很大的开销。

如果您有一个值类型的集合并正在迭代它们,则每次读取都会发生这种情况,然后将这些项目拆箱(与过程相反)只是为了读取值!

泛型集合对于存储在其中的类型是强类型的,因此不需要进行装箱或拆箱。

Firstly, the stack and heap are implementation details. a value type isnt defined by being on the stack. there is nothing to say that the concept of stack and heap will be used for all systems able to host the CLR:
Link

That aside:

when a value type is boxed, the data in that value type is read, an object is created, and the data is copied to the new object.
if you are boxing all the items in a collection, this is a lot of overhead.

if you have a collection of value types and are iterating over them, this will happen for each read, then the items are then unboxed (the reverse of the process) just to read a value!!

Generic collections are strongly typed to the type being stored in them, and therefore no boxing or unboxing needs to occur.

雾里花 2024-10-06 07:48:11

以下是关于以下问题的回复拆箱/装箱部分。

我不确定它是如何实现的
单声道,但通用接口会有所帮助
因为编译器创建了一个新的
每个特定类型的函数
使用不同类型(内部,有
有几种情况可以利用
相同的生成函数)。如果一个
具体类型的函数是
生成的,不需要
装箱/拆箱类型。

这就是 Collections.Generic 的原因
库在 .NET 2.0 上大受欢迎
因为不再需要集合
拳击并变得更加
高效。

关于为什么泛型比装箱/拆箱范围之外的其他集合更好,是因为它们也强制类型。您不再可以轻易地扔掉一个可以容纳任何类型的集合。它可以在编译时防止错误,而不是在运行时看到错误。

Here is a response around the unboxing/boxing portion.

I'm not sure how it is implemented in
mono, but generic interfaces will help
because the compiler creates a new
function of the specific type for each
different type used (internally, there
are a few cases where it can utilize
the same generated function). If a
function of the specific type is
generated, there is no need to
box/unbox the type.

This is why the Collections.Generic
library was a big hit at .NET 2.0
because collections no longer required
boxing and became significantly more
efficient.

In regards to why are generics better then other collections outside the boxing/unboxing scope is that they also force type. No longer can you readily toss a collection around which can hold any type. It can prevent bugs at compile time, versus seeing them at run time.

得不到的就毁灭 2024-10-06 07:48:11

MSDN 有一篇不错的文章:装箱和拆箱(C# 编程指南)

对于简单的分配,装箱和拆箱是计算成本较高的过程。当值类型被装箱时,必须分配和构造一个新对象。在较小程度上,拆箱所需的转换在计算上也很昂贵。

装箱用于在垃圾收集堆中存储值类型。装箱是值类型到类型对象或由该值类型实现的任何接口类型的隐式转换。装箱值类型会在堆上分配一个对象实例并将该值复制到新对象中。

拆箱是从类型对象到值类型或从接口类型到实现该接口的值类型的显式转换。拆箱操作包括:

  • 检查对象实例以确保它是给定值类型的装箱值。

  • 将实例中的值复制到值类型变量中。

另请查看:探索 C# Boxing

并阅读 Jeffrey Richter 的类型基础知识。这里两个示例章节以及 Jeffrey Richter 的《CLR》中的完整目录via C#”(Microsoft Press,2010) 他不久前发表过。

还有 Jeffrey Richter 的书《CLR via C#》中的一些注释:

可以使用称为装箱的机制将值类型转换为引用类型。

在内部,当值类型的实例被装箱时会发生以下情况:

  1. 内存是从托管堆中分配的。分配的内存量是
    值类型字段所需的大小加上两个额外的开销成员(
    托管上的所有对象所需的类型对象指针和同步块索引)
    堆。

  2. 值类型的字段被复制到新分配的堆内存中。

  3. 返回对象的地址。这个地址现在是一个对象的引用;值类型现在是引用类型。 C# 编译器会自动生成装箱值类型实例所需的 IL 代码,但您仍然需要了解内部发生的情况,以便了解代码大小和性能问题。


注意。应该注意的是,FCL 现在包含一组新的通用集合类,这使得非通用集合类变得过时。例如,您应该使用 System.Collections.Generic.List 类而不是 System.Collections.ArrayList
班级。通用集合类比非通用集合类提供了许多改进。例如,API得到了清理和改进,集合类的性能也得到了很大的提高。但最大的改进之一是通用集合类允许您使用值类型的集合,而不需要对集合中的项目进行装箱/拆箱。这本身就极大地提高了性能,因为在托管堆上创建的对象要少得多,从而减少了应用程序所需的垃圾收集次数。此外,您将获得编译时类型安全性,并且由于转换更少,您的源代码将更加干净。这将在第 12 章中进行更详细的解释,
“泛型。”


我不想在这里过度引用整章。阅读他的书,您会获得一些有关过程的详细信息并获得一些答案。顺便说一句,在网络上和许多书籍中都可以回答你的问题。这是你必须了解的基础知识。

MSDN has a nice article: Boxing and Unboxing (C# Programming Guide)

In relation to simple assignments, boxing and unboxing are computationally expensive processes. When a value type is boxed, a new object must be allocated and constructed. To a lesser degree, the cast required for unboxing is also expensive computationally.

Boxing is used to store value types in the garbage-collected heap. Boxing is an implicit conversion of a value type to the type object or to any interface type implemented by this value type. Boxing a value type allocates an object instance on the heap and copies the value into the new object.

Unboxing is an explicit conversion from the type object to a value type or from an interface type to a value type that implements the interface. An unboxing operation consists of:

  • Checking the object instance to make sure that it is a boxed value of the given value type.

  • Copying the value from the instance into the value-type variable.

Check also: Exploring C# Boxing

And read Jeffrey Richter's Type fundamentals. Here Two sample chapters plus full TOC from Jeffrey Richter's "CLR via C#" (Microsoft Press, 2010) he published some time ago.

Also some notes from Jeffrey Richter's book CLR via C#:

It’s possible to convert a value type to a reference type by using a mechanism called boxing.

Internally, here’s what happens when an instance of a value type is boxed:

  1. Memory is allocated from the managed heap. The amount of memory allocated is the
    size required by the value type’s fields plus the two additional overhead members (the
    type object pointer and the sync block index) required by all objects on the managed
    heap.

  2. The value type’s fields are copied to the newly allocated heap memory.

  3. The address of the object is returned. This address is now a reference to an object; the value type is now a reference type. The C# compiler automatically produces the IL code necessary to box a value type instance, but you still need to understand what’s going on internally so that you’re aware of code size and performance issues.


Note. It should be noted that the FCL now includes a new set of generic collection classes that make the non-generic collection classes obsolete. For example, you should use the System.Collections.Generic.List class instead of the System.Collections.ArrayList
class. The generic collection classes offer many improvements over the non-generic equivalents. For example, the API has been cleaned up and improved, and the performance of the collection classes has been greatly improved as well. But one of the biggest improvements is that the generic collection classes allow you to work with collections of value types without requiring that items in the collection be boxed/unboxed. This in itself greatly improves performance because far fewer objects will be created on the managed heap thereby reducing the number of garbage collections required by your application. Furthermore, you will get compile-time type safety, and your source code will be cleaner due to fewer casts. This will all be explained in further detail in Chapter 12,
“Generics.”


I don't want overquote full chapter here. Read his book and you gain some details on process and receive some answers. And BTW, answer to your question quite a few here on SO, around Web and in many books. It is fundamental knowledge you certainly have to understand.

南冥有猫 2024-10-06 07:48:11

以下是 Eric Lippert 的有趣读物(关于值类型的真相):
链接

关于您的声明的 :

Box 将值类型(堆栈对象)扔到 System.Object 中并将其存储在堆上。 Unbox 将保存该值类型的堆上的对象解包,然后将其扔回到堆栈上,以便可以使用它。

Here is an interesting read from Eric Lippert (The truth about value types):
Link

regarding your statement:

Box throws the value type (stack object) into a System.Object and stores it on the heap Unbox unpackages that object on the heap holding that value type and throws it back on the stack so it can be used.

梦在深巷 2024-10-06 07:48:11
  1. 需要这样做,因为在 IL 级别,值类型与引用类型有不同的指令(ldfldldflda ,检查反汇编的方法,该方法调用 someValueType.ToString()someReferenceType.ToString() 并且您会看到指令是不同的)。

    这些指令不兼容,因此,当您需要将值类型作为对象传递给方法时,需要将该值包装在引用类型中(装箱)。这是低效的,因为运行时需要复制值类型,然后创建一个新的装箱类型才能传递一个值。

  2. 泛型速度更快,因为值类型可以存储为值而不是引用,因此不需要装箱。以 ArrayListList 为例。如果要将 1 放入 ArrayList 中,CLR 需要对 int 进行装箱,以便将其存储在 对象中[]。但是 List 使用 T[] 来存储列表内容,因此 List 使用 int[] 这意味着 1 不需要装箱即可将其放入数组中。

  1. This needs to be done because at the IL level there are different instructions for value types than for reference types (ldfld vs ldflda , checkout the dissassembly for a method that calls someValueType.ToString() vs someReferenceType.ToString() and you'll see that the instructions are different).

    These instructions are not compatible so, when you need to pass a value type to a method as an object, that value needs to be wrapped in a reference type (boxing). This is ineficient because the runtime needs to copy the value type and then create a new boxing type in order to pass one value.

  2. Generics are faster because value types can be stored as values and not references so no boxing is needed. Take ArrayList vs List<int>. If you want to put 1 into an ArrayList, the CLR needs to box the int so that it can be stored in a object[]. List<T> however, uses a T[] to store the list contents so List uses a int[] which means that 1 doesn't need to be boxed in order to put it in the array.

痴情 2024-10-06 07:48:11

简单来说装箱和拆箱需要花费大量时间。为什么 - 因为从一开始就使用已知类型然后让它在运行时处理会更快。

  1. 对象集合中可以包含不同的项目:字符串、整数、双精度等,并且每次使用变量的操作都必须检查是否正确。
  2. 从一种类型转换为另一种类型需要时间。
  3. 通用更快并鼓励您使用它们,旧集合的存在是为了向后兼容

To put it simple boxing and unboxing takes alot of time. Why - beacuse it's faster to use known type from the start then let this handle for runtime.

  1. In colection of objects can contain differnt items : string, int, double, etc. and you must check every time that your operation with variable is corect.
  2. Convert from one type to enother takes time.
  3. Generic are much faster and encourage you to use them, old collections exist for backward compability
通知家属抬走 2024-10-06 07:48:11

假设我想在 List 中存储一堆 Long 类型的变量,但系统既不支持值类型泛型,也不支持装箱。存储这些值的方法是定义一个新类“BoxedLong”,它包含一个 Long 类型的字段“Value”。然后,要将值添加到列表中,可以创建一个 BoxedLong 的新实例,将其 Value 字段设置为所需的值,并将其存储在列表中。要从列表中检索值,可以从列表中检索 BoxedLong 对象,并从其 Value 字段中获取值。

当将值类型传递给需要对象的对象时,除了没有新的标识符名称之外,上述本质上是在幕后发生的事情。

当使用具有值类型的泛型时,系统不使用值持有者类并将其传递给期望使用对象的例程。相反,系统会创建一个新版本的例程,该例程将与相关值类型一起使用。如果将五种不同的值类型传递给通用例程,则会生成该例程的五个不同版本。一般来说,与使用值持有者类相比,这会产生更多的代码,但每次传入或检索值时,代码只需执行更少的工作。由于大多数例程将具有传入或传出的每种类型的许多值,因此生成例程的不同版本的成本将通过消除装箱/拆箱操作来补偿。

Suppose I want to store a bunch of variables of type Long in a List, but the system supported neither value-type generics nor boxing. The way to go about storing such values would be to define a new class "BoxedLong", which held a single field "Value" of type Long. Then to add a value to the list, one would create a new instance of a BoxedLong, set its Value field to the desired value, and store that in the list. To retrieve a value from the list, one would retrieve a BoxedLong object from the list, and take the value from its Value field.

When a value type is passed to something that expects an Object, the above is essentially what happens under the hood, except without the new identifier names.

When using generics with value types, the system doesn't use an value-holder class and pass it to routines which expect to work with objects. Instead, the system creates a new version of the routine that will work with the value type in question. If five different value types are passed to a generic routine, five different versions of the routine will be generated. In general, this will yield more code than would the use of a value-holder class, but the code will have to do less work every time a value is passed in or retrieved. Since most routines will have many values of each type passed in or out, the cost of generating different versions of the routine will be more than recouped by the elimination of boxing/unboxing operations.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文