在 .net 的内部,包含某些成员的结构的定义与具有相同字段和成员的类的定义相同,并且继承自System.ValueType
. 请注意,编译器不允许声明 aclass
继承ValueType
,但是当声明 a 时struct
,编译器“在幕后”声明了一个继承的类。
.net 中值类型的特殊之处在于运行时分配存储位置(变量、字段、参数等)的方式。当ValueType
声明不继承自的类型的存储位置时,运行时将为堆对象分配空间参考。相反,当声明继承自的类型的存储位置时ValueType
,运行时将为该类型的所有公共和私有字段分配空间。对于类似 的类型int
,系统会在正常类型系统之外分配一个属于特殊原始类型的私有字段。
请注意,值类型的存储位置并不真正保存该类型的实例。相反,它是该类型的一个实例,并包含该类型的所有字段。语句 likestruct1 = struct2
不会将值类型实例struct1
替换为实例struct2
。struct2
相反,它会从中的相应字段复制所有字段struct1
。同样,如果将值类型存储位置作为方法传递给过程而不使用ref
关键字,则传递的不是结构实例本身,而是其字段的内容。
如果需要将值类型的存储位置复制到非派生的类型ValueType
(例如Object
or IComparable
),系统将创建一个新的值类型的堆对象实例,将值类型的所有字段复制到该值类型new instancen 并将对该新实例的引用存储在目标存储位置。这个过程称为“装箱”。大多数编译器会隐式执行此操作,因此试图表现得好像值类型存储位置包含一个派生自ValueType
. 不过,重要的是要注意,这是一种错觉。如果 typeX
派生自Y
,一个有一个X
namedxx
和一个Y
namedyy
并且一个执行xx = yy
,这样的语句应该导致xx
和yy
引用相同的对象实例。如果xx
并且yy
不是从 派生的类型ValueType
,即使yy
持有从 派生的某物的实例,也会发生这种情况ValueType
。但是,如果xx
和/或yy
源自ValueType
. 在这种情况下,系统会将字段从一个实例复制到另一个(可能是新的)实例。