一尘不染

ValueTypes如何从Object(ReferenceType)派生而仍然是ValueTypes?

c#

C#不允许结构派生自类,但是所有ValueTypes都派生自Object。这种区别在哪里?

CLR如何处理此问题?


阅读 286

收藏
2020-05-19

共1个答案

一尘不染

C#不允许结构派生自类

您的陈述不正确,因此造成混淆。C# 确实
允许结构派生自类。所有结构都派生自同一类System.ValueType,该类派生自System.Object。并且所有枚举都派生自System.Enum。

更新:一些(现在已删除)评论中有些混乱,有必要澄清。我会问一些其他问题:

结构是否衍生自基本类型?

显然是的。我们可以通过阅读规范的第一页看到这一点:

所有C#类型(包括基本类型(例如int和double))都从单个根对象类型继承。

现在,我注意到规范在这里夸大了这种情况。指针类型不是从对象派生的,并且接口类型和类型参数类型的派生关系比此草图指示的要复杂。但是,很明显,所有结构类型都是从基本类型派生的。

我们还有其他方法可以知道结构类型是从基本类型派生的吗?

当然。结构类型可以覆盖ToString。如果不是其基本类型的虚拟方法,那么它覆盖什么?因此,它必须具有基本类型。该基本类型是一个类。

我可以从自己选择​​的类中派生用户定义的结构吗?

显然没有 这并不意味着结构不是从类派生的 。结构派生自一个类,从而继承该类的可继承成员。实际上, 需要
从特定的类派生Enum结构:需要枚举,必须从Enum派生,必须从派生结构ValueType。由于这些是 必需的 ,因此C#语言 禁止
您在代码中声明派生关系。

为什么要禁止它?

需要 某种关系
,语言设计者可以选择:(1)要求用户键入所需的咒语,(2)将其设为可选,或(3)禁止它。每个都有优缺点,C#语言设计师根据每个细节都选择了不同的内容。

例如,const字段必须是静态的,但禁止说它们是因为这样做首先是无意义的转义,其次意味着存在非静态const字段。但是,即使开发人员别无选择,重载运算符也必须标记为静态。开发人员很难相信操作符重载是实例方法。这消除了用户可能会认为“静态”暗示“虚拟”也是可能的担忧。

在这种情况下,要求用户说他们的结构是从ValueType派生的,这似乎仅仅是多余的词,这意味着该结构 可以 从另一种类型派生。为了消除这两个问题,C#
禁止 在代码中声明结构是从基本类型派生的,尽管很明显。

同样,所有委托类型都源自MulticastDelegate,但是C#要求您 不要 这样说。

因此,现在我们已经确定 C# 中的 所有结构都源自一个类

从类 继承继承 之间有什么关系? __

许多人对C#中的继承关系感到困惑。继承关系非常简单:如果结构,类或委托类型D是从类类型B派生的,那么B的可继承成员也是D的成员。就这么简单。

当我们说一个结构是从ValueType派生出来的时,对于继承是什么意思?简单地说,ValueType的所有可继承成员也是该结构的成员。例如,这就是结构获得其实现的方式ToString。它是从结构的基类继承的。

所有可继承成员?当然不是。私人成员可遗传吗?

是。基类的所有私有成员也是派生类型的成员。如果呼叫站点不在该成员的 可访问域中则按
名称呼叫这些成员当然是非法的。仅因为您拥有成员并不意味着可以使用它!

现在,我们继续原始答案:


CLR如何处理此问题?

非常好。:-)

使值类型成为值类型的原因是它的实例是 按value复制的 。使引用类型成为引用类型的原因是其实例是 通过引用复制的
。您似乎有一种信念,认为值类型和引用类型之间的 继承 关系在某种程度上是特殊且不寻常的,但是我不理解这种信念是什么。
继承与事物的复制方式无关。

这样看。假设我告诉您以下事实:

  • 有两种盒子,红色盒子和蓝色盒子。

  • 每个红色框都是空的。

  • 有三个特殊的蓝色框,分别称为O,V和E。

  • O不在任何盒子内。

  • V在O内部。

  • E在V内部。

  • V内没有其他蓝框。

  • E内没有蓝框。

  • 每个红色框位于V或E中。

  • 除O以外的每个蓝框本身都位于一个蓝框内。

蓝色框是引用类型,红色框是值类型,O是System.Object,V是System.ValueType,E是System.Enum,“内部”关系是“派生自”。

如果您有很多硬纸皮和很多耐心,那是一套完全一致和直接的规则,可以轻松实现自己的规则。一个盒子是红色还是蓝色与里面的东西无关。在现实世界中,完全有可能在蓝色框内放置一个红色框。在CLR中,使值类型继承自引用类型是完全合法的,只要它是System.ValueType或System.Enum。

因此,让我们改写您的问题:

ValueTypes如何从Object(ReferenceType)派生而仍然是ValueTypes?

每个红色框(值类型)如何可能在框O(System.Object)的内部(派生自该框)(是蓝色框(引用类型),而仍然是红色框(值类型))?

当您这样说时,希望它是显而易见的。没有什么可以阻止您在框V内放置一个红色框,该框位于框O内,该框为蓝色。为什么会有?


附加更新:

琼最初的问题是关于如何 可能的
值类型是从引用类型派生的。我最初的回答并没有真正解释CLR用来解释以下事实的任何机制:我们在具有完全不同表示形式的两件事之间具有派生关系,即所引用的数据是否具有对象标头,同步块,是否出于垃圾回收目的拥有自己的存储空间,等等。这些机制很复杂,太复杂了,无法一口气解释。CLR类型系统的规则比我们在C#中看到的稍微简化的样式要复杂得多,例如,在框式和未框式的类型之间没有明显的区别。泛型的引入还导致将许多其他复杂性添加到CLR。

2020-05-19