考虑以下情况:
int a = 42;
// Reference equality on two boxed ints with the same value
Console.WriteLine( (object)a == (object)a ); // False
// Same thing - listed only for clarity
Console.WriteLine(ReferenceEquals(a, a)); // False
显然,每个装箱指令都会分配一个封装的Int32的单独实例,这就是为什么它们之间的引用相等性失败的原因。此页面似乎表明这是指定行为:Box 指令将“原始”(未装箱)值类型转换为对象引用(类型 O)。 这通过创建一个新对象并将数据从值类型复制到新分配的对象来完成。
但这必须是这种情况吗?为什么CLR不选择保存装箱的Int32值的“缓存”,或者甚至更强大的,对于所有基本值类型(它们都是不可变的)使用公共值?我知道Java有类似的东西。
在没有泛型的时代,它是否有助于减少大量由小整数组成的大型ArrayList的内存要求以及GC工作量?我也确信存在一些现代.NET应用程序,它们使用泛型,但由于某种原因(反射、接口赋值等),会产生大量的装箱分配,而可以通过(似乎很简单的)优化来大幅减少。
那么原因是什么呢?我没有考虑的一些性能影响(我怀疑测试项目是否在缓存中将导致净性能损失,但我知道什么呢)?实现困难?与不安全代码有关的问题?破坏向后兼容性(我想不出任何良好编写的程序应该依赖于现有行为的好原因)?还是其他原因?
编辑:我真正建议的是“常见”的基元的静态缓存,就像Java做的那样。有关示例实现,请参见Jon Skeet的答案。我理解,针对任意的可能是可变的值类型或动态地在运行时“记忆”实例是完全不同的问题。
编辑:更改标题以确保清晰度。
Int32
应该具有这种“缓存”行为,还是所有基本值类型都应该具有?用户定义的值类型呢?对于后者可能是“不”,那么前者呢? - jason