关于值类型的混淆

问题描述:

如果我声明Object类的实例,我很困惑一点。它将被保留在堆上,但是当我声明时,从System.ValueType派生的任何基本类型实例(它是从Object类进一步派生的),那么Object类所使用的部分也保留在堆栈上。关于值类型的混淆

这是为什么,或者是这种情况,对象类没有空间?

+3

阅读Skeet:http://www.yoda.arachsys.com/csharp/parameters.html – 2010-01-29 21:20:25

+1

我对这个问题的回答可能有所帮助:http://*.com/questions/1978589/why-do-structs需要装箱 – 2010-01-29 21:28:05

+0

@Mehrdad,你的解释非常有用,知道它非常有趣,在较低的层次上,一个值不会继承任何东西。这是主要的问题,我假设它将System.Object作为它的一部分,因为它是他的基类,并且进一步必须有一些System.Object的私有数据。 – waheed 2010-01-30 01:29:29

你的推理似乎是这样的:

  • System.Int32是从System.Object派生
  • 派生类型始终奠定了在内存中以同样的方式作为其基本类型
  • 因此,System.Int32与System.Object一样布置在内存中。

是吗?

第二个前提是错误的。派生和内存布局几乎没有任何关系。你相信这个前提是真实的吗?如果是这样,是什么让你相信它?

更新:我认为这将有助于描述如何调用一个值类型的方法。

假设你已经有了一个值类型:

struct S { 
    public int x; 
    public override string ToString() { return "Hello!" + x; } 
} 
... 
S s = new S(); 
s.x = 0x00112233; 
s.ToString(); 

我们产生什么码?代码是这样的:

  • 为s.x在栈上保留四个字节。
  • 将字节00 11 22 33写入该内存。
  • 调用方法S.ToString,将引用传递给我们刚刚在堆栈上分配的内存位置。

为什么我们需要在堆栈上存储s.x的四个字节以外的任何东西?我们拥有所有我们需要的东西来完成调用:对包含S实例的变量的引用,以及我们调用的确切方法实现的确切名称和位置。没有必要在任何地方存储任何与System.Object有关的事情。没有“被对象类使用的部分”;我们不需要这样的事情,所以没有这样的事情。

+0

是的,这似乎是我想的方式。原因是我认为对象是一个单独的实体,假设它会在一个地方(即堆栈或堆),感谢纠正我。 – waheed 2010-01-30 00:03:49

通常,请参阅Eric Lippert的博客:the stack is an implementation detail。价值类型的基本特征是它们被价值传递。 System.ValueType实际上是从System.Object继承的,但你可以说价值类型是以一种特殊的方式处理的:它们总是被值复制。

+0

Eric Lippert的博客真的很有帮助,谢谢 – waheed 2010-01-30 00:47:11

.Net值类型是总是分配在堆栈上。对?

不,对不起,但并不总是

如果声明值类型为函数中的局部变量,那么,它会在栈上分配。

如果值类型是类中的成员,那么它将作为对象的一部分存储在堆上。

+1

P.S.事实上,Jon Skeet在去年的这个时候为我澄清了这一点。感谢Jon :) – 2010-01-29 21:37:48

+3

除非局部变量在迭代器块中,或者是匿名方法或lambda表达式的封闭外部变量。 – 2010-01-29 22:40:37

+0

@Eric Lippert:谢谢,这很有道理。 – 2010-01-30 00:40:30

从ValueType派生的任何东西都由编译器处理。它不是作为堆中的对象分配的,而是以内联方式分配的,即作为堆栈中的局部变量或作为另一个对象的成员。

值类型没有任何额外的数据,如对象所具有的。对象具有类型标识符和对虚拟方法表的引用,但值类型不需要这两者中的任何一个。所以,例如一个Int32只需要四个字节的实际数据。