装箱和拆箱
可能的重复:
什么是装箱和拆箱以及交易是什么折扣?
好的,我了解装箱和拆箱时会发生什么的基本概念。
Box 将值类型(堆栈对象)扔进 System.Object 并将其存储在堆上 Unbox 会将该对象在堆上保存该值类型的对象解包,并将其扔回到堆栈上,以便可以使用它。
这是我不明白的地方:
为什么需要这样做...具体的现实世界示例
为什么泛型这么有效吗?他们说因为泛型不需要拆箱或装箱,好吧..我不明白为什么...泛型背后是什么
为什么泛型比其他类型更好。例如,我们可以说其他集合吗?
所以总而言之,我不明白这一点在现实世界中的应用程序中的代码,然后进一步了解它如何使泛型更好......为什么在使用泛型时它不需要首先执行任何操作。
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:
Why would this need to be done...specific real-world examples
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
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
object
变量中保存int
时,就需要进行装箱。int
的通用集合包含int[]
而不是object[]
。int
放入非泛型集合后面的object[]
需要将int
装箱。将
int
放入泛型集合后面的int[]
中不会涉及任何装箱。int
in anobject
variable.int
s contains anint[]
instead of anobject[]
.int
into theobject[]
behind a non-generic collection requires you to box theint
.Putting an
int
into theint[]
behind a generic collection does not invlove any boxing.首先,栈和堆是实现细节。值类型不是通过在堆栈上定义的。毫无疑问,堆栈和堆的概念将用于所有能够托管 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.
以下是关于以下问题的回复拆箱/装箱部分。
关于为什么泛型比装箱/拆箱范围之外的其他集合更好,是因为它们也强制类型。您不再可以轻易地扔掉一个可以容纳任何类型的集合。它可以在编译时防止错误,而不是在运行时看到错误。
Here is a response around the unboxing/boxing portion.
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.
MSDN 有一篇不错的文章:装箱和拆箱(C# 编程指南)
另请查看:探索 C# Boxing
并阅读 Jeffrey Richter 的类型基础知识。这里两个示例章节以及 Jeffrey Richter 的《CLR》中的完整目录via C#”(Microsoft Press,2010) 他不久前发表过。
还有 Jeffrey Richter 的书《CLR via C#》中的一些注释:
我不想在这里过度引用整章。阅读他的书,您会获得一些有关过程的详细信息并获得一些答案。顺便说一句,在网络上和许多书籍中都可以回答你的问题。这是你必须了解的基础知识。
MSDN has a nice article: Boxing and Unboxing (C# Programming Guide)
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#:
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.
以下是 Eric Lippert 的有趣读物(关于值类型的真相):
链接
关于您的声明的 :
Here is an interesting read from Eric Lippert (The truth about value types):
Link
regarding your statement:
需要这样做,因为在 IL 级别,值类型与引用类型有不同的指令(
ldfld
与ldflda
,检查反汇编的方法,该方法调用someValueType.ToString()
与someReferenceType.ToString()
并且您会看到指令是不同的)。这些指令不兼容,因此,当您需要将值类型作为对象传递给方法时,需要将该值包装在引用类型中(装箱)。这是低效的,因为运行时需要复制值类型,然后创建一个新的装箱类型才能传递一个值。
泛型速度更快,因为值类型可以存储为值而不是引用,因此不需要装箱。以
ArrayList
与List
为例。如果要将1
放入ArrayList
中,CLR 需要对int
进行装箱,以便将其存储在对象中[]
。但是List
使用T[]
来存储列表内容,因此 List 使用int[]
这意味着1
不需要装箱即可将其放入数组中。This needs to be done because at the IL level there are different instructions for value types than for reference types (
ldfld
vsldflda
, checkout the dissassembly for a method that callssomeValueType.ToString()
vssomeReferenceType.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.
Generics are faster because value types can be stored as values and not references so no boxing is needed. Take
ArrayList
vsList<int>
. If you want to put1
into anArrayList
, the CLR needs to box theint
so that it can be stored in aobject[]
.List<T>
however, uses aT[]
to store the list contents so List uses aint[]
which means that1
doesn't need to be boxed in order to put it in the array.简单来说装箱和拆箱需要花费大量时间。为什么 - 因为从一开始就使用已知类型然后让它在运行时处理会更快。
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.
假设我想在 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.