考虑:
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
为所有原始值类型(都是不可变的)保存装箱 s 的“缓存”,甚至更强大的通用值?我知道Java有这样的东西。
ArrayList
在没有泛型的时代,对于主要由小整数组成的大数据,它不会对减少内存需求和 GC 工作量有很大帮助吗?我也确信存在几个确实使用泛型的现代.NET 应用程序,但无论出于何种原因(反射、接口分配等),运行大型装箱分配,可以通过(似乎是)大量减少简单的优化。
那么是什么原因呢?我没有考虑到一些性能影响(我怀疑测试该项目是否在缓存中等是否会导致净性能损失,但我知道什么)?实施困难?不安全代码的问题?打破向后兼容性(我想不出一个好的程序应该依赖现有行为的任何充分理由)?或者是其他东西?
编辑:我真正建议的是“常见”原语的静态缓存,就像 Java 所做的那样。有关示例实现,请参阅 Jon Skeet 的回答。我知道在运行时对任意、可能可变的值类型或动态“记忆”实例执行此操作是完全不同的事情。
编辑:为清楚起见更改了标题。