对Point的其他修改
对TraceID属性的读取与写入定义在标号8中,而使用在标号12中。
三个构造函数(标号9、10、11)全部会创建新的Point实例,所以它们需要为ID分配一个唯一的值,且其他的成员函数只会对现有的实例进行操作,而不会修改任何ID值。初始化只会在当一个对象创建时才会发生,因此也需要一个新的ID,而赋值操作发生在对象创建之后,所以在此不需要新的ID。
在标号12中,GetHashCode返回一个int,其正是ID所需的类型。同样,这个函数也能返回一个值,从而保证有一个唯一的哈希值。(当然了,如果ID的类型为unsigned或long long,就需要把它缩减为一个int类型。)
至于是否包含ID前缀,全在ToString中完成,见标号13。
Initonly字段 在非本地类中,如果一个字段声明中带有initonly标识符,其通常为一个在ctor初始化过程、构造函数体、或一个静态构造函数中的左值,而在其他情况中,其为一个右值。(特别要说明,一个静态的initonly字段只能被静态的构造函数所修改,而一个实例initonly字段只能被实例构造函数所修改。)除了当类第一次使用,或一个实例被创建时之外,都可以把这个字段当作只读类型,例如,某些工程数据类型有一张静态系统表,在每次程序运行时,其值都必须从一个文件中读出,但之后,就当作只读类型,例3就是这样一种情况。
例3:
using namespace System;
public ref class EngineeringData { /*1*/ static initonly array<double>^ coefficients; /*2*/ static EngineeringData() { int elementCount; //找出需要多大的数组 // elementCount = ... coefficients = gcnew array<double>(elementCount); for (int i = 0; i < elementCount; ++i) { // coefficients[i] = ... } } public: /*3*/ static property double Coeff[int] { double get(int index) { return coefficients[index]; } } }; int main() { double d; try { /*4*/ d = EngineeringData::Coeff[2]; } catch (IndexOutOfRangeException^ ex) { //处理异常 } } |
保存了系数的静态数组在标号1中声明为initonly,在静态构造函数中,打开了一个包含系数的文件,在确定数目后分配了相应大小的数组,并从文件中读取数值,保存到数组中。
与其让数组成为public或让程序员用下标来直接访问数组,倒不如让数组隐藏在一个只读的命名索引属性之后。(方括号表示了索引属性。)在本例中,是以逗号隔开的索引列表,这意味着,可以使用一个下标来索引到这个类,如标号4所示。(与多维数组下标相似,索引访问一个索引属性是使用了[]中的逗号分隔索引列表。)
C++/CLI默认情况下还允许一个索引属性名作为一个关键字,也就是说,一个实例名可被直接索引,而无须使用任何成员名。然而,这只对实例索引的属性可行,所以在此不能使用。同样地,属性名为Coeff。
一个initonly字段不是一个编译时命名常量,因此,它无须包含一个带有常量的初始化过程,且initonly也不会限制是否带有一个标量。
如果一个类包含了带有初始化过程的任意initonly字段,它们会以声明的顺序,在静态构造函数执行之前被初始化。
那能把Point类中的nextAvailableID标为initonly吗?毕竟,它只会在构造函数中被修改,答案是不可以,因为它是一个静态成员,且它只能被静态构造函数所更新。
查看本文来源