2015-06-05 21 views
1

每一个人都知道,当我们将Struct(Value Type)传递给函数时,等待Object,发生装箱。为什么CLR在完成从结构到对象的投射时做拳击?

但是,结构自ValueType,其从对象继承继承...

实施例:

ArrayList a = new ArrayList(); 
Point p = new Point(5,6); 
a.Add(p); 

在此例如对盒装和加入的ArrayList。但p已经是对象(如果你做“p是对象”,你会变成真)。编译器是否检查元数据以查看所有继承层次以查看是否存在ValueType类以知道值类型是否应在堆栈上分配?而且,如果它在继承ValueType的层次结构中找到它,它不会继续看到内部类?

例如:编译器检查点元数据:从谁继承Point? TypeValue!好吧,我不会继续 - 是值类型

+0

,我认为你应该专注于“引用”和“价值”。此外,价值类型没有任何层次结构,因为它们都是封闭的。 –

+2

值类型不是“在堆栈上分配的”。考虑一个整数数组。你相信数组中的所有整数都分配在堆栈上吗?如果是这样,那么数组如何从分配它的方法中返回? –

+0

Eric Lippert先生,你的意思是,因为堆栈是1 MB,它不能包含大数组?这是合乎逻辑的......所以,它被装箱并保存在堆中? – zzfima

回答

1

但p已经是对象(如果你做“p是对象”,你会得到真实的)。

这并不意味着p的值已经是一个参考。

从C#规范7.10.10的is运营商 - 只要相关的部分,其中DPoint这里,和Tobject

  • 如果T是引用类型,结果是如果DT是相同类型,则为true;如果D是参考类型,并且存在从DT的隐式参考转换,则或者D是typ值e和从DT的拳击转换存在

重点是我的 - 我们处于最后的情况。有一个装箱转换从Pointobject,这就是为什么is回报true ......但是,这并不意味着你可以Point类型的值转换为object型(即参考)的值,而不拳...

1

struct,以及所有其他值类型都是对象(Eric Lippert在此解释:How do ValueTypes derive from Object (ReferenceType) and still be ValueTypes?)。

这并不意味着struct和所有其他值类型都是引用类型,它们被装箱成引用类型。因此,object和'参考类型'是不一样的! 012 Jonathan Skeet解释说,隐式转换在这里也被考虑到了,所以这就是为什么你会看到这种行为。

3

考虑结构的一些性质,第一:

  1. 在C#中,所有的结构从类System.ValueType,进而从System.Object继承隐含继承。
  2. 在C#,一个结构不能从任何其它结构继承。这样做的直接后果是,如果你有一个表达式,它的静态已知类型是一个结构类型,则表达式的实例具有运行时类型等于静态已知类型。 (简单来说,如果你有一个int表达,则包含实例,绝对是准确的int

运行时类型检查,情况很简单:

  • 如果你问一个struct无论是object,则CLR中查找相关的元数据和层次结构中发现System.Object,所以它回答true

对于编译时类型检查,编译器必须做出一些决定:

  • 如果一个结构表达被分配给值类型的存储位置,则:
    • 如果类型不一样,但有一个隐式转换定义,转换被调用,然后分配发生。
    • 如果没有隐式转换,但分配是有效的(目标结构类型是一样的源结构类型),分配直接发生。
  • 如果一个结构表达被分配给参考类型的存储位置,则:
    • 如果存在定义的隐式转换,转换被调用,然后分配发生。
    • 如果没有隐式转换,但分配是有效的(目标类是object或目标接口是该结构类型实现的接口),则发生装箱操作和然后分配发生。

注意,通过存储位置我的意思是变量,字段阵列插槽,方法的参数,等等。

因此,如果您将结构实例赋值给object变量,或者如果将结构实例作为参数传递给期望表达式为object的方法,则无关紧要(至少假设没有过载决议涉及) - 在这两种情况下,适用相同的规则。


(这种情况可能更复杂一点,但我相信上面覆盖了一般的情况。)