How do ValueTypes derive from Object (ReferenceType) and still be ValueTypes?(ValueTypes 如何从 Object (ReferenceType) 派生并且仍然是 ValueTypes?)
问题描述
C# 不允许结构派生自类,但所有 ValueTypes 都派生自 Object.这种区别在哪里?
C# doesn't allow structs to derive from classes, but all ValueTypes derive from Object. Where is this distinction made?
CLR 如何处理这个问题?
How does the CLR handle this?
推荐答案
C# 不允许结构派生自类
C# doesn't allow structs to derive from classes
您的陈述不正确,因此您感到困惑.C# 确实 允许结构派生自类.所有结构都派生自同一个类 System.ValueType,后者派生自 System.Object.并且所有枚举都派生自 System.Enum.
Your statement is incorrect, hence your confusion. C# does allow structs to derive from classes. All structs derive from the same class, System.ValueType, which derives from System.Object. And all enums derive from System.Enum.
更新:一些(现已删除)评论存在一些混淆,需要澄清.我会问一些额外的问题:
UPDATE: There has been some confusion in some (now deleted) comments, which warrants clarification. I'll ask some additional questions:
结构是否派生自基类型?
Do structs derive from a base type?
显然是的.我们可以通过阅读规范的第一页看到这一点:
Plainly yes. We can see this by reading the first page of the specification:
所有 C# 类型,包括 int 和 double 等基本类型,都继承自一个根对象类型.
All C# types, including primitive types such as int and double, inherit from a single root object type.
现在,我注意到规范夸大了这里的情况.指针类型不是从对象派生的,接口类型和类型参数类型的派生关系比这个草图所表明的要复杂.但是,很明显,所有结构类型都派生自基类型.
Now, I note that the specification overstates the case here. Pointer types do not derive from object, and the derivation relationship for interface types and type parameter types is more complex than this sketch indicates. However, plainly it is the case that all struct types derive from a base type.
还有其他我们知道结构类型从基类型派生的方式吗?
Are there other ways that we know that struct types derive from a base type?
当然.结构类型可以覆盖 ToString
.如果不是其基本类型的虚拟方法,它会覆盖什么?因此它必须有一个基本类型.该基类型是一个类.
Sure. A struct type can override ToString
. What is it overriding, if not a virtual method of its base type? Therefore it must have a base type. That base type is a class.
我可以从我选择的类中派生一个用户定义的结构吗?
May I derive a user-defined struct from a class of my choice?
显然没有.这并不意味着结构不派生自类.结构派生自一个类,因此继承了该类的可遗传成员.事实上,结构是需要从特定类派生的:枚举需要从 Enum
派生,结构需要从 ValueType
派生.因为这些是必需的,C#语言禁止你在代码中陈述派生关系.
Plainly no. This does not imply that structs do not derive from a class. Structs derive from a class, and thereby inherit the heritable members of that class. In fact, structs are required to derive from a specific class: Enums are required to derive from Enum
, structs are required to derive from ValueType
. Because these are required, the C# language forbids you from stating the derivation relationship in code.
为什么要禁止?
当关系是必需的时,语言设计者有以下选择:(1) 要求用户键入所需的咒语,(2) 使其成为可选的,或 (3) 禁止.每个都有优点和缺点,C# 语言设计者根据每个的具体细节做出了不同的选择.
When a relationship is required, the language designer has options: (1) require the user to type the required incantation, (2) make it optional, or (3) forbid it. Each has pros and cons, and the C# language designers have chosen differently depending on the specific details of each.
例如,要求 const 字段是静态的,但禁止说它们是,因为这样做首先是毫无意义的废话,其次,意味着存在非静态 const 字段.但是重载的操作符需要标记为静态,即使开发者别无选择;开发人员很容易相信运算符重载是实例方法.这超越了用户可能会相信静态"意味着说虚拟"也是一种可能性的担忧.
For example, const fields are required to be static, but it is forbidden to say that they are because doing so is first, pointless verbiage, and second, implies that there are non-static const fields. But overloaded operators are required to be marked as static, even though the developer has no choice; it is too easy for developers to believe that an operator overload is an instance method otherwise. This overrides the concern that a user may come to believe that the "static" implies that, say "virtual" is also a possibility.
在这种情况下,要求用户说他们的结构派生自 ValueType 似乎只是多余的废话,这意味着结构 可以 派生自另一种类型.为了消除这两个问题,C# 规定在代码中声明结构派生自基类型是非法,尽管很明显它确实如此.
In this case, requiring a user to say that their struct derives from ValueType seems like mere excess verbiage, and it implies that the struct could derive from another type. To eliminate both these problems, C# makes it illegal to state in the code that a struct derives from a base type, though plainly it does.
类似地,所有委托类型都派生自 MulticastDelegate
,但 C# 要求您不这么说.
Similarly all delegate types derive from MulticastDelegate
, but C# requires you to not say that.
所以,现在我们已经确定C# 中的所有结构都派生自一个类.
So, now we have established that all structs in C# derive from a class.
继承和类派生有什么关系?
很多人对C#中的继承关系感到困惑.继承关系非常简单:如果结构、类或委托类型 D 派生自类类型 B,那么 B 的可继承成员也是 D 的成员.就这么简单.
Many people are confused by the inheritance relationship in C#. The inheritance relationship is quite straightforward: if a struct, class or delegate type D derives from a class type B then the heritable members of B are also members of D. It's as simple as that.
当我们说结构派生自 ValueType 时,继承是什么意思?简单地说,ValueType 的所有可遗传成员也是结构的成员.例如,这就是结构获取 ToString
实现的方式;它继承自结构的基类.
What does it mean with regards to inheritance when we say that a struct derives from ValueType? Simply that all the heritable members of ValueType are also members of the struct. This is how structs obtain their implementation of ToString
, for example; it is inherited from the base class of the struct.
所有可遗传的成员?肯定不是.私人成员可以遗传吗?
All heritable members? Surely not. Are private members heritable?
是的.基类的所有私有成员也是派生类型的成员.如果调用站点不在成员的可访问域 中,则通过名称调用这些成员当然是非法的.有会员不代表可以使用!
Yes. All private members of a base class are also members of the derived type. It is illegal to call those members by name of course if the call site is not in the accessibility domain of the member. Just because you have a member does not mean you can use it!
我们现在继续原来的答案:
We now continue with the original answer:
CLR 如何处理这个问题?
How does the CLR handle this?
非常好.:-)
使值类型成为值类型的原因在于它的实例按值复制.使引用类型成为引用类型的原因在于它的实例通过引用复制.您似乎相信值类型和引用类型之间的继承关系有些特殊和不寻常,但我不明白这种信念是什么.继承与复制的方式无关.
What makes a value type a value type is that its instances are copied by value. What makes a reference type a reference type is that its instances are copied by reference. You seem to have some belief that the inheritance relationship between value types and reference types is somehow special and unusual, but I don't understand what that belief is. Inheritance has nothing to do with how things are copied.
这样看.假设我告诉你以下事实:
Look at it this way. Suppose I told you the following facts:
有两种盒子,红色的框和蓝框.
There are two kinds of boxes, red boxes and blue boxes.
每个红框都是空的.
有三个特殊的蓝色框,分别称为 O、V 和 E.
There are three special blue boxes called O, V and E.
O 不在任何框内.
V在O里面.
E 在 V 内.
V 内没有其他蓝色框.
No other blue box is inside V.
E 内没有蓝色框.
每个红框都在 V 或 E 中.
Every red box is in either V or E.
除了 O 之外的每个蓝色盒子本身都在一个蓝色盒子内.
Every blue box other than O is itself inside a blue box.
蓝色框为引用类型,红色框为值类型,O为System.Object,V为System.ValueType,E为System.Enum,内部"关系为派生自".
The blue boxes are reference types, the red boxes are value types, O is System.Object, V is System.ValueType, E is System.Enum, and the "inside" relationship is "derives from".
这是一套完全一致且简单明了的规则,如果您有大量的硬纸板和足够的耐心,您可以轻松地自己实施这些规则.盒子是红色还是蓝色与里面的东西无关;在现实世界中,将一个红色盒子放在一个蓝色盒子里是完全可能的.在 CLR 中,创建从引用类型继承的值类型是完全合法的,只要它是 System.ValueType 或 System.Enum.
That's a perfectly consistent and straightforward set of rules which you could easily implement yourself, if you had a lot of cardboard and a lot of patience. Whether a box is red or blue has nothing to do with what it's inside; in the real world it is perfectly possible to put a red box inside a blue box. In the CLR, it is perfectly legal to make a value type that inherits from a reference type, so long as it is either System.ValueType or System.Enum.
所以让我们重新表述你的问题:
So let's rephrase your question:
ValueTypes 如何从 Object (ReferenceType) 派生并且仍然是 ValueTypes?
How do ValueTypes derive from Object (ReferenceType) and still be ValueTypes?
作为
怎么可能每个红框(值类型)都在框 O(System.Object)内部(派生自)框 O(System.Object),它是一个蓝框(引用类型)并且仍然是红框(值类型)?
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 里面是蓝色的.为什么会有?
When you phrase it like that, I hope it's obvious. There's nothing stopping you from putting a red box inside box V, which is inside box O, which is blue. Why would there be?
附加更新:
Joan 最初的问题是关于值类型如何可能从引用类型派生.我最初的回答并没有真正解释 CLR 使用的任何机制来解释我们在具有完全不同表示的两个事物之间存在派生关系这一事实——即,所引用的数据是否具有对象标头、同步块,它是否拥有自己的用于垃圾收集的存储,等等.这些机制很复杂,太复杂了,无法用一个答案来解释.CLR 类型系统的规则比我们在 C# 中看到的稍微简化的规则要复杂得多,例如,在 C# 中,类型的盒装版本和非盒装版本之间没有明显的区别.泛型的引入也给 CLR 添加了大量额外的复杂性.有关详细信息,请参阅 CLI 规范,特别注意装箱和受限虚拟调用的规则.
Joan's original question was about how it is possible that a value type derives from a reference type. My original answer did not really explain any of the mechanisms that the CLR uses to account for the fact that we have a derivation relationship between two things that have completely different representations -- namely, whether the referred-to data has an object header, a sync block, whether it owns its own storage for the purposes of garbage collection, and so on. These mechanisms are complicated, too complicated to explain in one answer. The rules of the CLR type system are quite a bit more complex than the somewhat simplified flavour of it that we see in C#, where there is not a strong distinction made between the boxed and unboxed versions of a type, for example. The introduction of generics also caused a great deal of additional complexity to be added to the CLR. Consult the CLI specification for details, paying particular attention to the rules for boxing and constrained virtual calls.
这篇关于ValueTypes 如何从 Object (ReferenceType) 派生并且仍然是 ValueTypes?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:ValueTypes 如何从 Object (ReferenceType) 派生并且仍然是 ValueTypes?
基础教程推荐
- MS Visual Studio .NET 的替代品 2022-01-01
- SSE 浮点算术是否可重现? 2022-01-01
- 将 XML 转换为通用列表 2022-01-01
- 如何激活MC67中的红灯 2022-01-01
- 将 Office 安装到 Windows 容器 (servercore:ltsc2019) 失败,错误代码为 17002 2022-01-01
- c# Math.Sqrt 实现 2022-01-01
- rabbitmq 的 REST API 2022-01-01
- 有没有办法忽略 2GB 文件上传的 maxRequestLength 限制? 2022-01-01
- 如何在 IDE 中获取 Xamarin Studio C# 输出? 2022-01-01
- 为什么Flurl.Http DownloadFileAsync/Http客户端GetAsync需要 2022-09-30