System.ValueType 理解
我尝试创建一个ValueType
。
我知道创建一个结构会对我有所帮助。
我还尝试从 System.ValueType 派生一个类型,它是一个抽象类。
但我收到了编译器错误消息
“..无法从特殊类 System.ValueType 派生”
当我看到 ValueType
的元数据时,它看起来是一个常规的抽象类。任何非密封类都应该是可导出的。但System.ValueType
不是一个密封类。
是什么让它如此特别?
是 C# 编译器认为它很特殊吗?
如果是这样,是否建议将其作为编译器设计的规则?我的意思是它是公共语言规范的一部分吗?
I tried to create a ValueType
.
I understand that creating a struct would help me.
I also tried to derive a type from System.ValueType
which is an abstract class.
But I got a compiler error message
".. cannot derive from special class System.ValueType"
When I see the metadata of ValueType
, it looks to be a regular abstract class. Any non sealed class should be derivable. But System.ValueType
is not a sealed class.
What made it special?
Is it the C# compiler that senses it as special?
If so, is it recommended as a rule for compiler design? I mean is it part of Common Language Specification?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
ValueType 是一个善意的谎言。
内置数字类型(int、long、byte)、char、枚举和结构都是值类型。
这意味着它们对于对象类型具有不同的同一性和等价性概念。如果我执行 x = y 且 x 和 y 是引用类型,则 x 和 y 现在指向完全相同的对象。但是,如果我执行 x = y 且 x 和 y 是值类型,那么 x 和 y 现在是两个完全不同的对象,但碰巧是相同的。 (这也反映在
==
和Equals
中,尽管可以被覆盖)。(这是人们通过谈论堆栈和堆而转移注意力的地方,如果他们还没有这样做的话,实际上这是一个实现细节,虽然很重要,但不是值类型和引用类型之间的区别点)。
现在,基本上这一切都很好,但关于引用类型的一件事是它们都受益于从 System.Object 继承。值类型 int 并非如此,这也很好,因为它在很多方面都更好,它只是由可爱的 CPU 指令处理的四个字节的内存,而这些指令非常擅长这样做。尽管如此,有时能够将 int 视为也是从 System.Object 继承的还是很有用的,所以您可以。
当然,这意味着您可以使用 int 执行仅在 System.Object 上才有意义的操作,因此当您这样做时,int 会被“装箱”,然后可以再次“拆箱”。
这很棒,但是如果我们想做一些特定于值类型的事情怎么办?更重要的是,如果 CLR 的设计者这样做了(特别是,他们想要与上述基于值的等价性相关的值类型的 GetHashCode,而不是对象所具有的基于身份的等价性)怎么办?
为此,我们有 ValueType。系统将所有值类型视为从该类继承,而该类又从 Object 继承。枚举又继承自值类型,并且所有枚举类型都继承自它,从而允许所有枚举具有一些通用功能。
因此,如果您想处理所有值类型的超类,请使用 ValueType,但如果您想实际创建值类型,请根据需要创建结构体或枚举。
通用类型系统解释:
ValueType 的奇怪之处在于允许上述情况发生。
ValueType is a little white lie.
The built-in numeric types (int, long, byte), char, enums and structs are all value types.
This means that they have a different concepts of identity and equivalence to object types. If I do
x = y
and x and y are reference types, then x and y now point to precisely the same object. However, if I dox = y
and x and y are value types, then x and y are now two completely different objects that happen to be identical. (This is also reflected in==
andEquals
, though that can be overridden).(This is where people get sidetracked by talking about the stack and the heap, if they haven't already, really that's an implementation detail and while important, is not the point of the distinction between value and reference types).
Now, mostly this is all and good but one thing about reference types is that they all benefit from inheriting from System.Object. The value type int doesn't really, and that's good too as it's much better in many ways that it just be four bytes of memory handled by the lovely CPU instructions that are so good at doing so. Still, it's sometimes useful to be able to treat an int as if it also inherited from System.Object, and so you can.
Of course, this means that you may do things with int that only make sense to do on a System.Object, so when you do so the int is "boxed" and can then be "unboxed" again.
This is great, but what if we wanted to do something specific to value types? More to the point, what if the designers of the CLR did (in particular, they wanted a GetHashCode for value types that related to the value-based equivalence descibed above, rather than the identity-based equivalence that objects have)?
For this purpose we have ValueType. The system treats all value types as inheriting from this class, which in turn inherits from Object. Enum in turn inherits from value type and all enum types inherit from it, allowing some common functionality across all enums.
So, if you ever want to treat a superclass of all value types, use ValueType, but if you want to actually create a value type, create a struct or an enum as appropriate.
The Common Type System explanation:
The strangeness of ValueType is to allow the above to happen.
无法从 ValueType 派生是 C# 编译器特有的。如果我们查看托管 C++ 代码:
这两个代码都可以编译并且是相同的。当然,
会给出错误 C3050: a ref class不能继承自 'System::ValueType'。
不确定其他编译器允许什么。
如果要从 C# 中的 ValueType 派生,请使用结构而不是类,编译器会处理它。
Not being able to derive from ValueType is specific to the C# compiler. If we look at managed C++ code:
Both of these compile and are identical. Of course,
Will give error C3050: a ref class cannot inherit from 'System::ValueType'.
Not sure what other compilers allow.
If you want to derive from ValueType in C#, use struct and not class, and the compiler takes care of it.
结构是值类型。值类型很特殊,因为它们是在堆栈而不是堆上分配的。要从 ValueType “继承”,您必须创建一个结构体。
Structures are value types. Value types are special because they are allocated on the stack rather than the heap. To "inherit" from ValueType, you must create a struct.
C# 不允许从其他类继承值类型。值类型(结构体)可以实现接口。
C# does not allow value types to inherit from other classes. Value types (struct) can implement interfaces.
您不能直接子类化 ValueType。所有值类型都隐式派生自 ValueType。与引用类型不同,您不能从值类型派生新类型。但是,与引用类型一样,结构可以实现接口。
请参阅 MSDN 了解更多信息
you cannot subclass ValueType directly. All value types derives from ValueType implicitly. Unlike with reference types, you cannot derive a new type from a value type. However, like reference types, structs can implement interfaces.
see MSDN to know more
“类”扩展“System.Object”,“结构”扩展“System.ValueType”。如果您可以使类扩展“System.ValueType”,那么“struct”关键字就没有多大意义了。
是
是。完成任何给定的事情应该只有一种方法。一旦提供了两种做某事的方法,你就会让一切变得更加复杂。一般规则。
A 'class' extends 'System.Object', a 'struct' extends 'System.ValueType'. If you could make a class extend 'System.ValueType', then there wouldn't be much point to the 'struct' keyword.
Yes
Yes. There should only be one way to accomplish any given thing. As soon as two methods of doing something are provided, you've just make everything more complicated. General rule.
这就是让我困惑的地方...Enum 是从 ValueType 派生的。这让我认为上述只是编译器限制。
This is what perplexes me... Enum is derived from ValueType. Which makes me think the above is just a compiler restriction.