我正在阅读有关拳击的内容,书中说“拳击可以正式定义为通过将变量存储在System.Object
中将值类型显式转换为相应的引用类型的过程“。 (重点补充)
我的问题不是关于拳击,但这让我思考 - System.Object实例如何以及在何处存储分配给它的值/变量/对象。所以我不仅想知道
object objShort = 5;
但也
object someOtherObj = someReallyComplicatedObject;
我一直在寻找,包括here (MSDN System.Object),我没有看到任何描述System.Object实例如何实际存储其数据的地方。
对象只是简单地存储指向分配给它的对象的指针,或者在装箱的情况下,指向堆栈上值类型的指针?
(乔恩,请原谅我,如果这也出现在你的书中。我已经订购了它,它已经开始了!)
答案 0 :(得分:8)
拳击的描述不准确。创建的对象不仅仅是裸System.Object
的实例;每个值类型实际上都有自己的“隐藏”对应引用类型,它只是从ValueType
派生的类实现与值类型相同的接口,并且具有值类型类型的字段。这当然是我对它的看法,至少,它大致是CLI规范描述它的方式。 System.Object
本身 没有任何存储空间。
我还想纠正“存储变量”部分 - 装箱将值存储在一个对象中。该值可能是变量的值,也可能是方法调用的结果,或者其他任何内容。
当然,对于参考类型,根本不需要拳击。你真的需要区分引用和对象 - 一旦你在脑海中清楚地了解了这两个,大多数其他事情都很容易理解。然后记住变量的值永远不是一个对象 - 它只是一个值类型值或一个引用(或一个指针:)
(哦,这在C#深度中有点有些,但不是很详细。但你可能对Eric Lippert的帖子"The Truth About Value Types"感兴趣。)
答案 1 :(得分:6)
想象一下,有一个通用的引用类型,如下所示:
sealed class Box<T> : System.ValueType where T : struct
{
private T value;
public Box(T t)
{
this.value = t;
}
}
还有一堆其他狡猾的东西:
Box<T>
到T
的显式转换运算符。T
到Box<T>
的隐式转化运算符,它只是调用构造函数。 概念,从int到object的装箱转换只是调用从int
到Box<int>
的隐式转换运算符。
当然,实际上没有Box<T>
这样的类型,如果有的话,它必须充满古怪的东西;你不能正常覆盖GetType,你不能正常地在一个类中扩展ValueType,它的可行类型的行为很奇怪,依此类推。所有这些细节都是CLR的实现细节,但它有助于想象CLR只是创建一个非常特殊类型的实例来完成装箱和拆箱的工作。
答案 2 :(得分:2)
CLR中引用类型的对象(包括C#)存储有一些元数据,这些元数据描述了它是什么类型的对象,它的锁状态和垃圾收集信息等,以及实际数据该对象存储。
当(值类型的)值被加框时,将为值类型创建为引用类型创建的相同类型的结构。它是在用于引用类型对象的同一托管堆中创建的,并且它受到相同的垃圾回收。 (因此它不是对堆栈上的值的引用。)