由于Int32是一个结构,这意味着它是一个System.ValueType(它继承了System.Object),当我将一个Integer传递给一个需要Object的函数时,CLR为什么要将它包装起来呢?
CLR是否假定Object始终是引用类型?
认为ValueType“是”一个对象有点令人困惑,但是当你必须将它作为“对象”传递时,你需要把它装箱......
我是唯一一个对此感到疑惑的人吗?
答案 0 :(得分:1)
从Object派生的类型始终不是引用类型,而是Object类型的变量始终包含引用。假设您想将实际值存储在Object中;那你怎么决定Object值需要多大?
编译时已知值类型的变量具有可以分配空间的已知大小,但是能够“包含”任何值类型的Object无法提前调整大小。一个逻辑解决方案是让Object变量包含对盒装对象的特殊类型的引用,从而根据盒子的类型动态分配“box”的大小。
一些稍微技巧性的说明:
上述问题的另一个解决方案是将Object视为对内存中任意位置的引用,这将防止必须创建盒装副本。这是它在C中的完成方式,例如,您可以在其中创建指向堆栈上的值的指针,然后将其传递给另一个函数以供使用。这可能是非常危险的,例如,如果函数决定保留该指针并在稍后的某个未定义时使用它,则会发生这种情况。由于调用堆栈已经改变,该指针现在指向与最初预期完全不同的东西,写入它几乎肯定会产生灾难性的副作用。
作为托管运行时,.NET的部分目标是提供一个“安全”环境,在这种情况下,这些特定类型的故障不会发生。权衡的一部分是禁止持久直接引用堆栈内存,当你想在包含引用的变量中“持久化”值类型的内容时需要装箱。这曾经是.NET 1.1中集合的性能问题,但在.NET 2.0中添加Generics意味着拳击事件不常发生。