System.ValueType 理解

发布于 2024-09-14 13:13:21 字数 456 浏览 3 评论 0原文

我尝试创建一个ValueType

我知道创建一个结构会对我有所帮助。

我还尝试从 System.ValueType 派生一个类型,它是一个抽象类。

但我收到了编译器错误消息

..无法从特殊类 System.ValueType 派生

当我看到 ValueType 的元数据时,它看起来是一个常规的抽象类。任何非密封类都应该是可导出的。但System.ValueType 不是一个密封类。

  1. 是什么让它如此特别?

  2. 是 C# 编译器认为它很特殊吗?

  3. 如果是这样,是否建议将其作为编译器设计的规则?我的意思是它是公共语言规范的一部分吗?

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.

  1. What made it special?

  2. Is it the C# compiler that senses it as special?

  3. If so, is it recommended as a rule for compiler design? I mean is it part of Common Language Specification?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

紫竹語嫣☆ 2024-09-21 13:13:21

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,但如果您想实际创建值类型,请根据需要创建结构体或枚举。


通用类型系统解释:

结构是隐式派生自 System.ValueType 的值类型,而 System.ValueType 又派生自 System.Object。结构对于表示内存需求较小的值以及将值作为按值参数传递给具有强类型参数的方法非常有用。在 .NET Framework 类库中,所有原始数据类型(Boolean、Byte、Char、DateTime、Decimal、Double、Int16、Int32、Int64、SByte、Single、UInt16、UInt32 和 UInt64)都定义为结构体。

与类一样,结构定义数据(结构的字段)和可以对该数据执行的操作(结构的方法)。这意味着您可以调用结构上的方法,包括在 System.Object 和 System.ValueType 类上定义的虚拟方法,以及在值类型本身上定义的任何方法。换句话说,结构可以具有字段、属性和事件,以及静态和非静态方法。您可以创建结构实例,将它们作为参数传递,将它们存储为局部变量,或者将它们存储在其他值类型或引用类型的字段中。结构体也可以实现接口。

值类型在几个方面也不同于类。首先,虽然它们隐式继承自System.ValueType,但它们不能直接继承自任何类型。同样,所有值类型都是密封的,这意味着不能从它们派生出其他类型。它们也不需要构造函数。

对于每种值类型,公共语言运行时都会提供相应的装箱类型,该类型是与值类型具有相同状态和行为的类。当值类型的实例传递给接受 System.Object 类型的参数的方法时,该实例将被装箱。当控制从接受值类型作为按引用参数的方法调用返回时,它被拆箱(即从类的实例转换回值类型的实例)。某些语言要求您在需要装箱类型时使用特殊语法;其他人在需要时自动使用盒装类型。当您定义值类型时,您同时定义了装箱类型和未装箱类型。

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 do x = 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 == and Equals, 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:

A structure is a value type that derives implicitly from System.ValueType, which in turn is derived from System.Object. A structure is very useful for representing values whose memory requirements are small, and for passing values as by-value parameters to methods that have strongly typed parameters. In the .NET Framework class library, all primitive data types (Boolean, Byte, Char, DateTime, Decimal, Double, Int16, Int32, Int64, SByte, Single, UInt16, UInt32, and UInt64) are defined as structures.

Like classes, structures define both data (the fields of the structure) and the operations that can be performed on that data (the methods of the structure). This means that you can call methods on structures, including the virtual methods defined on the System.Object and System.ValueType classes, and any methods defined on the value type itself. In other words, structures can have fields, properties, and events, as well as static and nonstatic methods. You can create instances of structures, pass them as parameters, store them as local variables, or store them in a field of another value type or reference type. Structures can also implement interfaces.

Value types also differ from classes in several respects. First, although they implicitly inherit from System.ValueType, they cannot directly inherit from any type. Similarly, all value types are sealed, which means that no other type can be derived from them. They also do not require constructors.

For each value type, the common language runtime supplies a corresponding boxed type, which is a class that has the same state and behavior as the value type. An instance of a value type is boxed when it is passed to a method that accepts a parameter of type System.Object. It is unboxed (that is, converted from an instance of a class back to an instance of a value type) when control returns from a method call that accepts a value type as a by-reference parameter. Some languages require that you use special syntax when the boxed type is required; others automatically use the boxed type when it is needed. When you define a value type, you are defining both the boxed and the unboxed type.

The strangeness of ValueType is to allow the above to happen.

倒带 2024-09-21 13:13:21

无法从 ValueType 派生是 C# 编译器特有的。如果我们查看托管 C++ 代码:

value class Foo {};
value class Foo : System::ValueType {};

这两个代码都可以编译并且是相同的。当然,

ref class Foo : System::ValueType {};

会给出错误 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:

value class Foo {};
value class Foo : System::ValueType {};

Both of these compile and are identical. Of course,

ref class Foo : System::ValueType {};

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.

稳稳的幸福 2024-09-21 13:13:21

结构是值类型。值类型很特殊,因为它们是在堆栈而不是堆上分配的。要从 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.

呆橘 2024-09-21 13:13:21

C# 不允许从其他类继承值类型。值类型(结构体)可以实现接口。

C# does not allow value types to inherit from other classes. Value types (struct) can implement interfaces.

寄与心 2024-09-21 13:13:21

您不能直接子类化 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

疯狂的代价 2024-09-21 13:13:21
  1. “类”扩展“System.Object”,“结构”扩展“System.ValueType”。如果您可以使类扩展“System.ValueType”,那么“struct”关键字就没有多大意义了。

  2. 是。完成任何给定的事情应该只有一种方法。一旦提供了两种做某事的方法,你就会让一切变得更加复杂。一般规则。

  1. 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.

  2. Yes

  3. 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.

┾廆蒐ゝ 2024-09-21 13:13:21

这就是让我困惑的地方...Enum 是从 ValueType 派生的。这让我认为上述只是编译器限制。

[Serializable, ComVisible(true)]
public abstract class Enum : ValueType, IComparable, IFormattable, IConvertible
{
  ...
}

This is what perplexes me... Enum is derived from ValueType. Which makes me think the above is just a compiler restriction.

[Serializable, ComVisible(true)]
public abstract class Enum : ValueType, IComparable, IFormattable, IConvertible
{
  ...
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文