我尝试创建一个ValueType。
我知道创建一个结构会对我有帮助。
我还尝试从System.ValueType派生一个类型,它是一个抽象类。
但我收到编译器错误消息“ ..无法从特殊类System.ValueType 派生”
当我看到ValueType的元数据时,它看起来是一个常规的抽象类。
是什么让它与众不同?
C#compilor是否感觉特别?
如果是这样,是否建议将其作为编译器设计的规则?我的意思是它是公共语言规范的一部分吗?
答案 0 :(得分:35)
ValueType是一个小小的谎言。
内置数值类型(int,long,byte),char,enums和structs都是值类型。
这意味着它们具有不同的身份概念和对象类型的等同性。如果我做x = y
并且x和y是引用类型,则x和y现在指向完全相同的对象。但是,如果我x = y
并且x和y是值类型,则x和y现在是两个完全不同的对象,恰好相同。 (这也反映在==
和Equals
中,但可以覆盖它。
(这是人们通过讨论堆栈和堆来讨论堆栈的问题,如果它们还没有,那么实际上这是一个实现细节,虽然重要但不是值和引用类型之间的区别点。)< / p>
现在,大多数情况下这一切都很好,但有关引用类型的一件事是它们都可以从继承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类型的参数的方法时,将其装箱。当控件从接受值类型作为by-reference参数的方法调用返回时,它被取消装箱(即,从类的实例转换回值类型的实例)。有些语言要求在需要盒装类型时使用特殊语法;其他人在需要时自动使用盒装类型。定义值类型时,您要定义盒装类型和未装箱类型。
ValueType的陌生感是允许上述情况发生。
答案 1 :(得分:3)
结构是价值类型。值类型是特殊的,因为它们是在堆栈而不是堆上分配的。要从ValueType“继承”,您必须创建一个结构。
答案 2 :(得分:2)
无法从ValueType派生特定于C#编译器。如果我们看一下托管C ++代码:
value class Foo {};
value class Foo : System::ValueType {};
这两个编译都是相同的。当然,
ref class Foo : System::ValueType {};
将给出错误C3050:ref类不能继承'System :: ValueType' 不确定其他编译器允许的内容。
如果要从C#中的ValueType派生,请使用struct而不是class,编译器会处理它。
答案 3 :(得分:1)
您不能直接将ValueType子类化。所有值类型都隐式地从ValueType派生。与引用类型不同,您无法从值类型派生新类型。但是,与引用类型一样,结构可以实现接口。
请参阅MSDN了解更多信息
答案 4 :(得分:1)
C#不允许值类型从其他类继承。值类型(struct)可以实现接口。
答案 5 :(得分:0)
'class'扩展'System.Object','struct'扩展'System.ValueType'。如果你可以让一个类扩展'System.ValueType',那么'struct'关键字就没那么重要了。
是
是。应该只有一种方法来完成任何给定的事情。一旦提供了两种做事方法,你就会让一切变得更加复杂。一般规则。
答案 6 :(得分:0)
这让我感到困惑...... Enum源于ValueType。这让我觉得上面只是一个编译器限制。
[Serializable, ComVisible(true)]
public abstract class Enum : ValueType, IComparable, IFormattable, IConvertible
{
...
}