ValueTypes如何从Object(ReferenceType)派生,仍然是ValueTypes?
C#不允许从类派生结构,但所有的ValueType派生自Object。 这个区别在哪里?
CLR如何处理这个问题?
C#不允许结构派生自类
你的陈述是不正确的,因此你的困惑。 C#允许结构派生自类。 所有结构派生自System.Object派生的同一类System.ValueType。 所有的枚举派生自System.Enum。
更新:在一些(现删除)评论中有一些混淆,需要澄清。 我会再问一些问题:
结构是否来源于基本types?
显然是的。 我们可以通过阅读规范的第一页来看到这一点:
所有C#types(包括基本types,如int和double)都从一个根对象typesinheritance而来。
现在,我注意到这个规范夸大了这里的情况。 指针types不是从对象派生的,而且接口types和types参数types的派生关系比本草图指示的更为复杂。 然而,显而易见,所有的结构types都是从一个基types派生的。
还有其他的方式,我们知道结构types派生自一个基types?
当然。 结构types可以覆盖ToString
。 如果不是它的基本types的虚拟方法,它是什么重写呢? 因此它必须有一个基types。 该基types是一个类。
我可以从我select的类派生一个用户定义的结构吗?
显然没有。 这并不意味着结构不是来自一个阶级 。 结构来自一个阶级,从而inheritance这个阶级的可遗传成员。 事实上,结构需要从一个特定的类派生:枚举需要从Enum
派生,结构必须派生自ValueType
。 因为这些是必需的 ,所以C#语言禁止你在代码中声明派生关系。
为什么禁止?
当需要关系时 ,语言devise者有以下select:(1)要求用户键入所需的咒语,(2)使其可选,或(3)禁止。 每个人都有优点和缺点,而C#语言devise师根据每个人的具体细节select了不同的方式。
例如,const字段必须是静态的,但是禁止说他们是因为这样做第一,毫无意义的措词,第二,意味着有非静态的const字段。 但重载操作符需要被标记为静态的,即使开发者没有select; 开发人员很容易认为运算符重载是一种实例方法。 这压倒了用户可能会认为“静态”意味着说“虚拟”也是一种可能性的担忧。
在这种情况下,要求用户说他们的结构派生自ValueType看起来仅仅是多余的语言,这意味着该结构可能来自另一种types。 为了消除这两个问题,C#在代码中声明一个结构派生自一个基本types是非法的 ,尽pipe显然是这样。
类似地,所有委托types都是从MulticastDelegate
派生的,但C#要求您不要这么说。
所以,现在我们已经确定, C#中的所有结构都来自一个类 。
inheritance和派生类之间的关系是什么?
很多人都被C#中的inheritance关系迷惑了。 inheritance关系非常简单:如果一个结构,类或委托typesD派生自一个类typesB,那么B的可遗传成员也是D的成员。就像这样简单。
当我们说结构派生自ValueType时,关于inheritance是什么意思? 简单地说,ValueType的所有可遗传成员也是结构的成员。 例如,结构体如何获得ToString
的实现; 它是从结构的基类inheritance的。
所有可遗传的成员? 当然不是。 私人成员是否可以遗传?
是。 基类的所有私有成员也是派生types的成员。 如果呼叫站点不在会员的可访问范围内,则按名称呼叫这些成员是非法的。 仅仅因为你有一个成员并不意味着你可以使用它!
我们现在继续原来的答案:
CLR如何处理这个问题?
非常好。 🙂
使值types成为值types的原因是它的实例是按值复制的 。 什么使引用types成为引用types是它的实例是通过引用来复制的 。 你似乎有一些信念,值types和引用types之间的inheritance关系是某种特殊和不寻常的,但我不明白这个信念是什么。 inheritance与如何复制事物无关。
这样看。 假设我告诉你以下事实:
-
有两种盒子,红色的盒子和蓝色的盒子。
-
每个红色的盒子都是空的。
-
有三个特殊的蓝色框,称为O,V和E.
-
O不在任何框内。
-
V在里面
-
E在五里面
-
五里面没有其他的蓝框。
-
E.里面没有蓝色的盒子
-
每个红色框都是V或者E
-
除O以外的每一个蓝色框都在蓝色框内。
蓝色框是引用types,红色框是值types,O是System.Object,V是System.ValueType,E是System.Enum,“内部”关系是“派生自”。
如果你有很多硬纸板和耐心的话,那么你可以很容易地实现自己的规则,这是一套完全一致和直接的规则。 盒子是红色还是蓝色与盒子内部没有任何关系; 在现实世界中,把一个红色的盒子放在一个蓝色的盒子里是完全可能的。 在CLR中,只要它是System.ValueType或System.Enum,就可以创build一个inheritance自引用types的值types,这是完全合法的。
所以我们来重述一下你的问题:
ValueTypes如何从Object(ReferenceType)派生,仍然是ValueTypes?
如
怎么可能每个红框(值types)都在里面(派生自)框O(System.Object),这是一个蓝框(引用types),仍然是一个红色框(值types)?
当你这样说时,我希望这是明显的。 没有任何东西可以阻止你把一个红色的盒子放在V盒子里面,盒子里面是蓝色的。 为什么会有?
附加更新:
Joan的原始问题是关于值types如何从引用types派生的可能性 。 我的原始答案并没有真正解释CLR用来解释这样一个事实,即我们在两个具有完全不同的表示的事物之间有一个派生关系,即被引用的数据是否有一个对象头,同步块,是否拥有自己的存储以用于垃圾回收等等。 这些机制是复杂的,太复杂,无法用一个答案来解释。 例如,CLRtypes系统的规则比我们在C#中看到的稍微简化一些,比如在一个types的盒装和非盒装版本之间没有很强的区别。 generics的引入也给CLR增加了很多额外的复杂性。 有关详细信息,请参阅CLI规范,特别注意拳击和受限虚拟呼叫的规则。
这是一个由CLR维护的有点人造的构造,以便允许所有types被视为System.Object。
值types从System.Object派生到System.ValueType ,这是特殊处理发生的地方(即CLR处理来自ValueType的任何types的装箱/取消装箱等)。
小的更正,C#不允许结构定制从任何东西派生,而不仅仅是类。 所有的结构可以做的是实现一个接口,这是非常不同的派生。
我认为回答这个问题的最好方法是ValueType
是特殊的。 它实质上是CLRtypes系统中所有值types的基类。 很难知道如何回答“CLR如何处理这个问题”,因为这只是CLR的一个规则。
你的陈述是不正确的,因此你的困惑。 C#允许结构派生自类。 所有结构派生自相同的类System.ValueType
所以我们来试试这个:
struct MyStruct : System.ValueType { }
这甚至不会编译。 编译器会提醒你“在接口列表中键入'System.ValueType'不是一个接口”。
当反编译Int32这是一个结构,你会发现:
公共结构Int32:IComparable,IFormattable,IConvertible {},没有提到它是从System.ValueType派生。 但在对象浏览器中,您确实发现Int32从System.ValueTypeinheritance。
所有这些让我相信:
我认为回答这个问题的最好方法是ValueType是特殊的。 它实质上是CLRtypes系统中所有值types的基类。 很难知道如何回答“CLR如何处理这个问题”,因为这只是CLR的一个规则。
一个盒装的值types实际上是一个引用types(它像一个走路,像一个庸医,所以有效的是一个)。 我会build议ValueType不是真正的值types的基本types,而是在转换为typesObject时将值types转换到的基本引用types。 非盒装值types本身在对象层次结构之外。