Possible Duplicates:
Why do we need boxing and unboxing in C#?
What is boxing and unboxing and what are the trade offs?可能重复:为什么我们需要在C#中装箱和拆箱?什么是拳击和拆箱,有什么权衡?
In C# what doe sit means: "Box and UnBox"?
在C#中,doe sit意味着什么:“Box and UnBox”?
Here an extract from MSDN where I founded the Text.
这里是我创建Text的MSDN的摘录。
But this convenience comes at a cost. Any reference or value type that is added to an ArrayList is implicitly upcast to Object. If the items are value types, they must be boxed when they are added to the list, and unboxed when they are retrieved. Both the casting and the boxing and unboxing operations decrease performance; the effect of boxing and unboxing can be very significant in scenarios where you must iterate over large collections.
但这种便利需要付出代价。添加到ArrayList的任何引用或值类型都隐式地向上转换为Object。如果项目是值类型,则在将它们添加到列表时必须将它们装箱,并在检索它们时取消装箱。铸造,装箱和拆箱操作都会降低性能;在必须迭代大型集合的情况下,装箱和拆箱的效果可能非常显着。
Thanks!
3 个解决方案
#1
27
Here is a more detailed explanation that looks at the internal of Common Language Runtime.
这是一个更详细的解释,它关注公共语言运行时的内部。
First, let's make the difference between value types and reference types:
首先,让我们区分值类型和引用类型:
- A value type is held on the stack and a copy of it is passed to called methods
- A reference value is held in the managed heap and the stack holds only a pointer (reference) to its location. The location, and not the object, is passed to called methods
值类型保存在堆栈上,并将其副本传递给调用的方法
引用值保存在托管堆中,并且堆栈仅包含指向其位置的指针(引用)。位置而不是对象被传递给被调用的方法
If you don't know what the stack is (don't be offended), it's a memory area that holds local variables in a method and addresses of caller functions used for return
instruction (just to be brief and provide a general answer). When you call a method, a sufficient area on the stack is statically allocated to it, so stack allocation is always called static allocation.
如果您不知道堆栈是什么(不要被冒犯),它是一个存储区域,它在方法中保存局部变量,并使用用于返回指令的调用函数的地址(只是简短并提供一般答案)。当您调用方法时,堆栈上的足够区域将静态分配给它,因此堆栈分配始终称为静态分配。
The heap, instead, is a memory area separated from the stack, property of the running process, in which allocation must be first demanded to the operating system, and that's why it's called dynamic allocation (if you don't run in an if statement, for example, memory may not be allocated for your process, instead stack is always allocated).
相反,堆是一个与堆栈分开的内存区域,它是运行进程的属性,必须首先向操作系统请求分配,这就是为什么它被称为动态分配(如果你不在if语句中运行)例如,可能不会为您的进程分配内存,而是始终分配堆栈)。
Just to make a final example on heap and stack: in languages such as C++, declaring int[100] a;
statically allocates 100*8 bytes on the stack (64-bit system assumed), while int* a = new int[100];
declares a 8 bytes (on 64-bit systems) area on the stack AND requests 800 more bytes on the heap, if and where available.
只是为了在堆和堆栈上做一个最后的例子:在C ++等语言中,声明int [100] a;静态地在堆栈上分配100 * 8个字节(假定为64位系统),而int * a = new int [100];在堆栈上声明一个8字节(在64位系统上)并在堆上请求800多个字节,如果可用的话。
Now let's talk about C#:
现在让我们谈谈C#:
Boxing
Since int is a value type, and is allocated on the stack, when you cast it to object or any other reference type (actually there is no other reference type from which int can inherit, but it's a general rule) the value must become necessarily a reference type. So a new area on the heap is allocated, the object is boxed inside it and the stack holds a pointer to it.
由于int是一个值类型,并且在堆栈上分配,当你将它转换为对象或任何其他引用类型时(实际上没有其他引用可以继承的引用类型,但它是一般规则),该值必须是必需的参考类型。因此,堆上的新区域被分配,对象被装入其中,并且堆栈包含指向它的指针。
Unboxing
Just the opposite: when you have a reference type, such as object, and want to cast it to a value type, such as to int, the new value must be held on the stack, so CLR goes to heap, un-boxes the value and copies it to the stack.
恰恰相反:当你有一个引用类型,比如object,并希望将它转换为一个值类型,比如int,新值必须保存在堆栈上,所以CLR转到堆,取消框值并将其复制到堆栈。
In other words
Remember the int[]
and int*
examples? Simply, when you have int
in C#, the runtime expects its stack location to hold the value but instead when you have object
, it expects its real value to be in the heap location pointed by the stack.
还记得int []和int *示例吗?简单地说,当您在C#中使用int时,运行时期望其堆栈位置保持该值,但是当您有对象时,它期望其实际值位于堆栈指向的堆位置。
#2
1
There are two different types in .net Framework.
.net Framework中有两种不同的类型。
ValueTypes such as int, double, single
ValueTypes,如int,double,single
ReferenceTypes ArrayList List and many, many more
ReferenceTypes ArrayList List以及许多,更多
Variables of type ValueTypes are stored in Stack ReferenceTyped variables are stored in heap
ValueTypes类型的变量存储在Stack ReferenceType中,变量存储在堆中
Variables of type ValueTypes store the VALUE ReferenceTyped variables store the REFERENCE to a value
ValueTypes类型的变量存储VALUE ReferenceTyped变量将REFERENCE存储到值
so if you copy a ValueType variable - there is a real copy of a value but if you copy a ReferenceType variable - you will get an additional reference to the SAME variable.
因此,如果复制ValueType变量 - 存在值的实际副本,但如果复制ReferenceType变量,则会获得对SAME变量的附加引用。
Boxing in your question means, that a valueType Variable (e.g. int) will be handled liked a reference Type Variable - .net gives it into a new box. So it will be encapsulated within the heap and there will be reference(s) to it.
在你的问题中装箱意味着,一个valueType变量(例如int)将像一个引用类型变量一样处理 - .net将它放入一个新的框中。所以它将封装在堆中,并且会有引用。
In case you want the value to be again in a valueType Variable you have to unbox it (take it out of the box). So the value will be taken out of the heap - and stored/given to the stack once again.
如果您希望将值再次置于valueType变量中,则必须将其取消装箱(将其从包装盒中取出)。因此,该值将从堆中取出 - 并再次存储/提供给堆栈。
#3
0
ArrayList stores only Objects. For a reference-type (like String
) this is no problem but for a ValueType (int, DateTime, ..) it is.
ArrayList仅存储对象。对于引用类型(如String),这是没有问题的,但对于ValueType(int,DateTime,..),它是。
These valuetypes need to be converted to an object before you can store them as plain Object. This "converting to object" is called "boxing" and takes a little bit of time.
在将这些值类型存储为普通对象之前,需要将这些值类型转换为对象。这种“转换为对象”被称为“拳击”,需要一点时间。
When you read the value back, you need to convert from Object to int
(or whatever it was). This is called "unboxing".
当您重新读取值时,需要将Object从Object转换为int(或其他任何内容)。这称为“拆箱”。
#1
27
Here is a more detailed explanation that looks at the internal of Common Language Runtime.
这是一个更详细的解释,它关注公共语言运行时的内部。
First, let's make the difference between value types and reference types:
首先,让我们区分值类型和引用类型:
- A value type is held on the stack and a copy of it is passed to called methods
- A reference value is held in the managed heap and the stack holds only a pointer (reference) to its location. The location, and not the object, is passed to called methods
值类型保存在堆栈上,并将其副本传递给调用的方法
引用值保存在托管堆中,并且堆栈仅包含指向其位置的指针(引用)。位置而不是对象被传递给被调用的方法
If you don't know what the stack is (don't be offended), it's a memory area that holds local variables in a method and addresses of caller functions used for return
instruction (just to be brief and provide a general answer). When you call a method, a sufficient area on the stack is statically allocated to it, so stack allocation is always called static allocation.
如果您不知道堆栈是什么(不要被冒犯),它是一个存储区域,它在方法中保存局部变量,并使用用于返回指令的调用函数的地址(只是简短并提供一般答案)。当您调用方法时,堆栈上的足够区域将静态分配给它,因此堆栈分配始终称为静态分配。
The heap, instead, is a memory area separated from the stack, property of the running process, in which allocation must be first demanded to the operating system, and that's why it's called dynamic allocation (if you don't run in an if statement, for example, memory may not be allocated for your process, instead stack is always allocated).
相反,堆是一个与堆栈分开的内存区域,它是运行进程的属性,必须首先向操作系统请求分配,这就是为什么它被称为动态分配(如果你不在if语句中运行)例如,可能不会为您的进程分配内存,而是始终分配堆栈)。
Just to make a final example on heap and stack: in languages such as C++, declaring int[100] a;
statically allocates 100*8 bytes on the stack (64-bit system assumed), while int* a = new int[100];
declares a 8 bytes (on 64-bit systems) area on the stack AND requests 800 more bytes on the heap, if and where available.
只是为了在堆和堆栈上做一个最后的例子:在C ++等语言中,声明int [100] a;静态地在堆栈上分配100 * 8个字节(假定为64位系统),而int * a = new int [100];在堆栈上声明一个8字节(在64位系统上)并在堆上请求800多个字节,如果可用的话。
Now let's talk about C#:
现在让我们谈谈C#:
Boxing
Since int is a value type, and is allocated on the stack, when you cast it to object or any other reference type (actually there is no other reference type from which int can inherit, but it's a general rule) the value must become necessarily a reference type. So a new area on the heap is allocated, the object is boxed inside it and the stack holds a pointer to it.
由于int是一个值类型,并且在堆栈上分配,当你将它转换为对象或任何其他引用类型时(实际上没有其他引用可以继承的引用类型,但它是一般规则),该值必须是必需的参考类型。因此,堆上的新区域被分配,对象被装入其中,并且堆栈包含指向它的指针。
Unboxing
Just the opposite: when you have a reference type, such as object, and want to cast it to a value type, such as to int, the new value must be held on the stack, so CLR goes to heap, un-boxes the value and copies it to the stack.
恰恰相反:当你有一个引用类型,比如object,并希望将它转换为一个值类型,比如int,新值必须保存在堆栈上,所以CLR转到堆,取消框值并将其复制到堆栈。
In other words
Remember the int[]
and int*
examples? Simply, when you have int
in C#, the runtime expects its stack location to hold the value but instead when you have object
, it expects its real value to be in the heap location pointed by the stack.
还记得int []和int *示例吗?简单地说,当您在C#中使用int时,运行时期望其堆栈位置保持该值,但是当您有对象时,它期望其实际值位于堆栈指向的堆位置。
#2
1
There are two different types in .net Framework.
.net Framework中有两种不同的类型。
ValueTypes such as int, double, single
ValueTypes,如int,double,single
ReferenceTypes ArrayList List and many, many more
ReferenceTypes ArrayList List以及许多,更多
Variables of type ValueTypes are stored in Stack ReferenceTyped variables are stored in heap
ValueTypes类型的变量存储在Stack ReferenceType中,变量存储在堆中
Variables of type ValueTypes store the VALUE ReferenceTyped variables store the REFERENCE to a value
ValueTypes类型的变量存储VALUE ReferenceTyped变量将REFERENCE存储到值
so if you copy a ValueType variable - there is a real copy of a value but if you copy a ReferenceType variable - you will get an additional reference to the SAME variable.
因此,如果复制ValueType变量 - 存在值的实际副本,但如果复制ReferenceType变量,则会获得对SAME变量的附加引用。
Boxing in your question means, that a valueType Variable (e.g. int) will be handled liked a reference Type Variable - .net gives it into a new box. So it will be encapsulated within the heap and there will be reference(s) to it.
在你的问题中装箱意味着,一个valueType变量(例如int)将像一个引用类型变量一样处理 - .net将它放入一个新的框中。所以它将封装在堆中,并且会有引用。
In case you want the value to be again in a valueType Variable you have to unbox it (take it out of the box). So the value will be taken out of the heap - and stored/given to the stack once again.
如果您希望将值再次置于valueType变量中,则必须将其取消装箱(将其从包装盒中取出)。因此,该值将从堆中取出 - 并再次存储/提供给堆栈。
#3
0
ArrayList stores only Objects. For a reference-type (like String
) this is no problem but for a ValueType (int, DateTime, ..) it is.
ArrayList仅存储对象。对于引用类型(如String),这是没有问题的,但对于ValueType(int,DateTime,..),它是。
These valuetypes need to be converted to an object before you can store them as plain Object. This "converting to object" is called "boxing" and takes a little bit of time.
在将这些值类型存储为普通对象之前,需要将这些值类型转换为对象。这种“转换为对象”被称为“拳击”,需要一点时间。
When you read the value back, you need to convert from Object to int
(or whatever it was). This is called "unboxing".
当您重新读取值时,需要将Object从Object转换为int(或其他任何内容)。这称为“拆箱”。