深入理解.NET中的值类型

在.NET框架中,值类型是数据结构的一种,它们在托管堆上分配内存。然而,在处理简单的数据结构时,如整数或坐标(x,y),直接在上分配这些值并使用标准的值类型语义会更加方便和高效。例如,声明一个整数时,不需要使用指针和new关键字来创建一个整数对象。相反,数值类型、布尔值、字符和日期等原始类型,以及结构体和枚举都是作为值类型声明的,这意味着它们在栈上分配,并像标准C++中的结构体或栈上变量一样声明和访问。

在托管C++中声明值类型时,使用新的__value关键字。例如,如果想要创建一个表示复数的数据类型,可以声明如下:

__value struct Complex { double real; double imaginary; };

值类型是在上创建的,并且可以直接访问。值类型声明如下:

Complex z;

并且使用点语法访问其成员:

z.real = 1.0; z.imaginary = -3.1415;

一旦包含值类型的内存被释放,该值类型的实例就会被销毁。因此,不允许引用值类型。如果允许,可能会导致引用指向一个无效的内存位置。值类型总是指向该类型的变量,并且不能为null。将值类型赋值给另一个变量时,会创建该值的副本。

因为值类型是托管类型,所以在创建时它们会被初始化为0。值类型可以包含引用类型,但这些引用类型将在托管堆上创建,而引用将存储在上。

值类型隐式继承自System.ValueType,鼓励用于行为类似于原始数据类型的类型、小型类型、不从其他数据类型继承或被继承的类型,以及不经常作为参数传递的类型(这会导致大量的内存分配和复制)。值类型可以继承托管接口,并可以覆盖其中定义的虚拟方法。

所有值类型的一个重要点是它们可以包含方法和字段,并且可以覆盖基接口中的虚拟方法。例如,可能希望覆盖复数类型的ToString方法,以便可以以格式化的方式呈现它:

__value struct Complex { double real; double imaginary; virtual String* ToString() { return String::Format("{0} + {1}i", real.ToString("N2"), imaginary.ToString("N2")); } };

装箱和解包是.NET的一个特性,它允许值类型作为引用类型传递。例如,.NET的String类的标准Format方法重写接受一个格式字符串和一个对象。格式字符串指定格式,对象在该格式字符串中使用{0}语法访问。一个整数不是从Object派生的,因此通常不能传递给这个函数。然而,通过装箱一个整数值,创建了一个包含整数值的对象,并且可以作为对象使用。语法如下:

object obj = __box(5);

这在托管堆上创建了一个包含值'5'的托管引用。现在这个对象可以在任何需要Object*对象的地方使用。

也可以声明装箱值类型,如下所示:

__box Complex* pZ = __box(z);

这给提供了一个可以在任何认为合适的地方使用的装箱对象,但在这样做的同时,保留了访问底层类型数据字段的能力:

pZ->real = 4; Complex w = *dynamic_cast(pZ);
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485