gpt4 book ai didi

c# - ValueTypes 如何从 Object (ReferenceType) 派生并仍然是 ValueTypes?

转载 作者:行者123 更新时间:2023-12-02 02:48:09 24 4
gpt4 key购买 nike

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

CLR 如何处理这个问题?

最佳答案

C# doesn't allow structs to derive from classes



你的陈述是不正确的,因此你的困惑。 C# 确实允许从类派生结构。所有结构都派生自同一个类 System.ValueType,后者派生自 System.Object。并且所有枚举都源自 System.Enum。

更新:在一些(现已删除)评论中存在一些混淆,需要澄清。我会问一些额外的问题:

Do structs derive from a base type?



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

All C# types, including primitive types such as int and double, inherit from a single root object type.



现在,我注意到规范在这里夸大了情况。指针类型不是从对象派生的,接口(interface)类型和类型参数类型的派生关系比这个草图显示的更复杂。然而,很明显,所有结构类型都是从基类型派生的。

Are there other ways that we know that struct types derive from a base type?



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

May I derive a user-defined struct from a class of my choice?



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

Why forbid it?



当需要某种关系时,语言设计者有以下选择:(1) 要求用户键入所需的咒语,(2) 使其成为可选的,或 (3) 禁止它。每个都有优点和缺点,C# 语言设计者根据每个的具体细节进行了不同的选择。

例如,const 字段必须是静态的,但禁止说它们是静态的,因为这样做首先是无意义的措辞,其次暗示存在非静态的 const 字段。但是,即使开发人员别无选择,也要求将重载运算符标记为静态;否则,开发人员很容易相信运算符重载是实例方法。这超越了用户可能会相信“静态”意味着“虚拟”也是一种可能性的担忧。

在这种情况下,要求用户说他们的结构派生自 ValueType 似乎只是多余的措辞,这意味着该结构可以从另一种类型派生。为了消除这两个问题,C# 规定在代码中声明结构派生自基类型是非法的,尽管很明显它确实如此。

类似地,所有委托(delegate)类型都源自 MulticastDelegate ,但 C# 要求您不要这么说。

所以,现在我们已经确定 C# 中的所有结构都派生自 类。

What is the relationship between inheritance and derivation from a class?



很多人被C#中的继承关系搞糊涂了。继承关系非常简单:如果结构、类或委托(delegate)类型 D 派生自类类型 B,那么 B 的可继承成员也是 D 的成员。就这么简单。

当我们说结构派生自 ValueType 时,继承是什么意思?简单地说,ValueType 的所有可遗传成员也是结构的成员。例如,这就是结构如何获取 ToString 的实现;它是从结构的基类继承的。

All heritable members? Surely not. Are private members heritable?



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

我们现在继续原来的答案:

How does the CLR handle this?



非常好。 :-)

使值类型成为值类型的原因是它的实例是 复制的值 。使引用类型成为引用类型的原因是它的实例是 由引用 复制。您似乎有一些信念,即值类型和引用类型之间的 继承 关系在某种程度上是特殊和不寻常的,但我不明白这种信念是什么。 继承与复制事物的方式无关。

这样看。假设我告诉你以下事实:
  • 有两种盒子,红色
    框和蓝色框。
  • 每个红框都是空的。
  • 有三个特殊的蓝色框,分别称为 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。

    所以让我们重新表述你的问题:

    How do ValueTypes derive from Object (ReferenceType) and still be ValueTypes?



    作为

    How is it possible that every red box (value types) is inside (derives from) box O (System.Object), which is a blue box (a reference Type) and still be a red box (a value type)?



    当你这样说时,我希望它是显而易见的。没有什么能阻止你在盒子 V 里面放一个红色的盒子,盒子在盒子 O 里面,盒子是蓝色的。为什么会有?

    附加更新:

    Joan 最初的问题是关于值类型如何可能从引用类型派生。我最初的回答并没有真正解释 CLR 用来解释我们在具有完全不同表示形式的两个事物之间具有派生关系这一事实的任何机制——即,所引用的数据是否具有对象头、同步块(synchronized block),它是否拥有自己的用于垃圾收集的存储,等等。这些机制很复杂,太复杂了,无法在一个答案中解释。 CLR 类型系统的规则比我们在 C# 中看到的稍微简化的风格复杂得多,例如,在 C# 中,类型的装箱和未装箱版本之间没有明显区别。泛型的引入也给 CLR 添加了大量额外的复杂性。有关详细信息,请参阅 CLI 规范,尤其要注意装箱和受限虚拟调用的规则。

    关于c# - ValueTypes 如何从 Object (ReferenceType) 派生并仍然是 ValueTypes?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1682231/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com