Ita*_*aro 63 .net c# generics boxing unboxing
.NET 1.0创建整数集合的方法(例如)是:
ArrayList list = new ArrayList();
list.Add(i); /* boxing */
int j = (int)list[0]; /* unboxing */
Run Code Online (Sandbox Code Playgroud)
使用它的代价是由于装箱和拆箱而缺乏类型安全性和性能.
.NET 2.0方式是使用泛型:
List<int> list = new List<int>();
list.Add(i);
int j = list[0];
Run Code Online (Sandbox Code Playgroud)
拳击的价格(据我所知)是需要在堆上创建一个对象,将堆栈分配的整数复制到新对象,反之亦然,以便取消装箱.
泛型的使用如何克服这个问题?堆栈分配的整数是否保留在堆栈上并从堆中指向(我想这不是这种情况,因为当它超出范围时会发生什么)?似乎仍然需要将其复制到堆栈外的其他地方.
真的发生了什么?
Dan*_*Tao 64
在集合方面,泛型可以通过T[]
内部利用实际数组来避免装箱/拆箱.List<T>
例如,使用T[]
数组来存储其内容.
的阵列,当然,是引用类型,因此(在CLR中,内容十分重要的当前版本)存储在堆上.但是因为它是a T[]
而不是a object[]
,所以数组的元素可以"直接"存储:也就是说,它们仍然在堆上,但是它们在数组的堆上而不是被装箱并且数组包含对那些盒子.
因此,对于a List<int>
,例如,您在数组中拥有的内容将"看起来"如下:
[ 1 2 3 ]
将此与a进行比较ArrayList
,使用an object[]
并因此"看"这样的东西:
[ *a *b *c ]
... where *a
等等是对象的引用(盒装整数):
*a -> 1 *b -> 2 *c -> 3
请原谅那些粗略的插图; 希望你知道我的意思.
Eri*_*ert 64
您的困惑是由于误解了堆栈,堆和变量之间的关系.这是考虑它的正确方法.
作为实现细节,可以在堆栈上分配保证短期存储的存储位置.在堆上分配可能长寿的存储位置.请注意,这并未说明"值类型总是在堆栈上分配".值类型并不总是在堆栈上分配:
int[] x = new int[10];
x[1] = 123;
Run Code Online (Sandbox Code Playgroud)
x[1]
是一个存储位置.它是长寿的; 它可能比这种方法寿命更长.因此它必须在堆上.它包含int的事实是无关紧要的.
你正确地说为什么盒装int是昂贵的:
装箱的价格是需要在堆上创建一个对象,将堆栈分配的整数复制到新对象,反之亦然,以便取消装箱.
你出错的地方是说"堆栈分配整数".分配整数的位置无关紧要.重要的是它的存储包含整数,而不是包含对堆位置的引用.价格是需要创建对象并进行复制; 这是唯一相关的成本.
那么为什么通用变量代价不高呢?如果你有一个T类型的变量,并且T被构造为int,那么你有一个int,period类型的变量.int类型的变量是存储位置,它包含int.该存储位置是在堆栈上还是堆上是完全不相关的.相关的是存储位置包含一个int,而不是包含对堆上某些东西的引用.由于存储位置包含int,因此您不必承担装箱和拆箱的成本:在堆上分配新存储并将int复制到新存储.
那现在清楚了吗?