C#不允许从类派生结构
你的说法不正确,所以你很困惑。C#是吗?允许结构从类派生。所有结构都来自同一个类System.ValueType,该类派生于System.Object。所有枚举都来自System.Enum。
更新:在一些(现在删除的)评论中出现了一些混乱,需要澄清。我再问几个问题:
结构是从基类型派生的吗?
显然是的。通过阅读规范的第一页,我们可以看到这一点:
所有C#类型,包括int和Double等基元类型,都是从单个根对象类型继承的。
现在,我注意到规范夸大了这里的情况。指针类型不是从对象派生的,接口类型和类型参数类型的派生关系比此草图所指示的要复杂得多。但是,很明显,所有的struct类型都是从基类型派生的。
我们是否有其他方法知道结构类型是从基类型派生出来的?
好的。结构类型可以覆盖ToString
..如果不是它的基本类型的虚拟方法,它将覆盖什么?因此,它必须有一个基类型。这个基类型是一个类。
我可以从我选择的类中派生出用户定义的结构吗?
显然没有。这并不意味着结构不是从类派生的。..结构派生自类,从而继承该类的可遗传成员。实际上,结构是所需从特定类派生:枚举必须从Enum
,则需要从ValueType
..因为这些是所需,C#语言禁止您可以从代码中说明派生关系。
为什么要禁止?
当一段关系所需,语言设计器有以下选项:(1)要求用户键入所需的咒语,(2)使其可选,或(3)禁止使用。每个设计人员各有优缺点,C#语言设计人员根据每个设计人员的具体细节做出不同的选择。
例如,Const字段被要求是静态的,但是禁止说它们是静态的,因为这样做首先是没有意义的语句,其次,意味着存在非静态Const字段。但是,重载操作符必须标记为静态的,即使开发人员别无选择;开发人员很容易认为操作符重载是一个实例方法。这压倒了用户可能会相信“静态”意味着,比如说“虚拟”也是一种可能性的担忧。
在这种情况下,要求用户说他们的结构是从ValueType派生的,这看起来仅仅是多余的语句,这意味着结构能派生自另一种类型。为了消除这两个问题,C#制作了它非法在代码中声明结构是从基类型派生的,尽管它显然是从基类型派生的。
类似地,所有委托类型都派生自MulticastDelegate
,但C#要求你不说出来。
所以,现在我们已经确定C#中的所有结构都是从一个类派生出来的。.
之间的关系是什么?继承和从类派生?
许多人对C#中的继承关系感到困惑。继承关系非常简单:如果结构、类或委托类型D来自类型B,则B的可遗传成员也是D的成员。
当我们说一个结构从ValueType派生出来时,它对继承意味着什么?简单地说,ValueType的所有可遗传成员也都是结构的成员。结构是如何获得它们的实现的。ToString
例如,它是从结构的基类继承的。
所有可遗传的成员?当然不是。私人成员可以遗传吗?
是。基类的所有私有成员也是派生类型的成员。当然,如果调用站点不在可达域那个成员。仅仅因为你有一个会员并不意味着你可以使用它!
我们现在继续原来的答覆:
CLR如何处理这个问题?
非常好。*-)
使值类型的原因是它的实例是按值复制..使引用类型的原因是它的实例是引用复制..你似乎相信继承价值类型和引用类型之间的关系在某种程度上是特殊和不寻常的,但我不明白这种信念是什么。继承与复制事物的方式无关。
从这边看。假设我告诉你以下事实:
蓝色框是引用类型,红色框是值类型,O是System.Object,V是System.ValueType,E是System.Enum,“内部”关系是“派生的”。
如果你有大量的纸板和耐心,这是一套完全一致而又直截了当的规则,如果你有大量的纸板和耐心,你可以很容易地实现它。一个盒子是红色的还是蓝色的与它的内部无关;在现实世界中,把一个红色的盒子放进一个蓝色的盒子里是完全可能的。在CLR中,创建从引用类型继承的值类型是完全合法的,只要它是System.ValueType或System.Enum。
让我们重新表述一下你的问题:
ValueTypes是如何从对象(引用类型)派生而仍然是ValueTypes的?
如
如何使每个红色框(值类型)都在(派生自)方框O(System.Object)中,该框是蓝色框(引用类型),但仍然是红色框(值类型)?
当你这样说的时候,我希望这是显而易见的。没有什么能阻止你把一个红色的盒子放进盒子V里面,它在盒子O里面,是蓝色的。为什么会有?
另一项最新情况:
琼最初的问题是关于它是怎样的可能值类型派生自引用类型。我最初的回答并没有真正解释CLR使用的任何机制来解释这样一个事实,即我们在两件事之间有一个派生关系-即所引用的数据是否有一个对象头、一个同步块、它是否拥有自己的用于垃圾收集的存储,等等。这些机制很复杂,太复杂,无法用一个答案来解释。CLR类型系统的规则比我们在C#中看到的稍微简单的风格要复杂得多,例如,在C#中,类型的装箱版本和未装箱版本之间没有很大的区别。泛型的引入也给CLR增加了许多额外的复杂性。有关详细信息,请参阅CLI规范,特别注意装箱规则和受限的虚拟调用。