这取决于你戴的眼镜。如果你有“实现”眼镜,那么你会看到任何引用类型值都有一个对象头。这使得它们继承 System.Object。对象头有两个字段,同步块存储各种信息,如哈希码和调用 Monitor.Enter() 的线程 ID。重要的字段是第二个字段,方法表指针。标识对象类型。方法表包含类方法的地址,它总是以 Object 实现的方法 Equals、GetHashCode 和 ToString 开头。
戴着同样的眼镜,一个值类型的值没有这个对象头。它只占用存储值所需的空间量。一个字节用于 bool,两个字节用于 Char,四个字节用于 int,等等。这使得值类型非常有效。
您可以戴的第二副眼镜是“类型系统”眼镜。值类型值始终可以转换为对象。然后回来。这种转换称为拳击转换。返回称为拆箱。快点戴上实现眼镜,你会发现你确实得到了一个带有这两个字段的对象,方法表指针标识了值类型。方法表有额外的方法指针。与 IConvertible 类似,这是一个由值类型实现的接口。除了这两个字段之外,对象的其余部分由值类型值位占用。在装箱转换之前它仍然是一个简单值时具有的相同位。装箱的对象和所有引用类型的对象一样,存在于垃圾收集堆上。
在绝大多数情况下,C# 或 VB.NET 编译器完全自动应用装箱转换。您不必自己在代码中编写演员表。例如,您可以调用 ToString 或 IConvertible 方法之一,您将免费获得装箱转换。
这产生了值类型继承自 System.Object 的错觉。这是一个相当不错的错觉,任何戴“类型系统”眼镜的人都会坚持认为值类型绝对继承自 Object。如果您戴“实施”眼镜,那么您往往会担心拳击。它经过高度优化,但肯定不是免费的。进行转换会花费 cpu 周期,并且装箱的值类型值会占用更多空间并产生垃圾。泛型集合类型已完全取代旧的 System.Collection 类的原因之一。