数组:一种包含若干个相同类型变量的数据结构,而且这些变量都可以通过计算索引进行访问。数组中有个秩,它表示和每个数字元素关联的索引个数;数组的秩又被称为数组的维度;一维数组就是秩为1,几维数组秩就是几。维度的长度不是数组类型的组成部分,只是与数组类型的实例相关联,它是在运行时创建实例时确定的;如果数组的一个或多个维度的长度为零,则称该数组为空。
12.1数组类型
数组类型:表示一个非数组类型后跟一个或多个秩说明符:
数组类型的秩由数组类型中最左边的秩说明符给定:秩说明符指定该数组的秩等于秩说明符中","标记的个数加1。
数组类型的元素类型就是去掉最左边的秩说明符后剩下的表达式的类型:若形式是T[R],则秩是R,元素类型为非数组元素类型T;
若形式是T[R][R1]...[RN],则秩为R,元素类型为T[R1]...[RN]。
实质上,在解释数组类型时,先从左到右读取秩说明符,最后才读取非数组元素类型。比如类型int[][,,][,]表示一个一维数组,该一维数组的元素类型为三维数组,该三维数组的元素类型为二维数组,该二维数组的元素类型为int。
在运行时,数组类型的值可以为null,或是对该数组类型的某个实例的引用。
System.Array类型是所有数组类型的抽象基类型。存在从任何数组类型到System.Array的隐式转化,也存在从System.Array到任何数组类型的显示转换。值得注意的是,System.Array本身不是数组类型,相反,它是一个从中派生所有数组类型的类类型。
12.2数组创建
数组实例由数组创建表达式创建,在第七章和第十章有写到哦,或由包含数组初始值设定项的字段声明或局部变量声明创建。
创建数组实例时,必须确定秩和各维度的长度,在实例的整个生存期内是保持不变的。数组实例一定是数组类型。
System.Array类型是不能实例化的抽象类型。
由数组创建表达式创建的数组的元素总是被初始化为它们的默认值。
12.3数组元素访问
我们可以使用形式为A[I1,I2,I3....,IN]的"元素访问"表达式来访问数组元素,其中A是数组类型的表达式。数组元素访问的结果是变量,即由下标选定的数组元素。
12.4数组成员
每个数组类型都继承由System.Array类型所声明的成员。
12.5数组协方差
对于任意两个引用类型A和B,如果存在从A到B的隐式转换或显式转换,则一定存在从数组类型A[R]到B[R]的相同的引用转换,R可以是任何给定的秩说明符,但两个数组类型必须相同的R。这种关系称为数组协方差。这么说吧,数组协方差意味着数组A[R]的值实际上可能是对数组B[R]的实例的引用(如果存在从B到A的隐式转换)。
由于存在数组协方差,因此对引用类型数组的元素的复制操作会包括一个运行时检查,以确保正在赋给数组元素的值确实是允许的类型。比如:
Fill方法中对array[i]的赋值隐式地包含一个运行时检查,以确保由value引用的对象是null或与array的实际元素类型兼任的类型的实例。所以前两次方法调用成功,最后一次出错了,会引发System.ArrayTypeMismatchExcetion,因为int类型不能存储在string数组中。
具体说,数组协方差不能延伸到值类型的数组。
12.6数组初始值设定项
数组初始值设定项可用于字段声明、局部变量声明和数组创建表达式中。
数组初始值设定项包含一系列变量设定项,它们包括在"{}"标记中并且用","标记分隔。每个变量初始值设定项是一个表达式或是一个嵌套的数组初始值设定项。
数组初始值设定项所在位置的上下文确定了正在被初始化的数组的类型。在数组创建表达式中,数组类型后紧跟着初始值设定项。在字段或变量声明中,数组类型就是所声明的字段或变量的类型。当数组初始值设定项在字段或变量声明中时,如:
int[] a={0,2,4,6,8};等效后面这个数组创建表达式的简写: int[] a =new int{0,2,4,6,8};
对于一维数组,数组初始值设定项必须包含一个表达式序列,这些表达式是与数组的元素类型兼任的赋值表达式。表达式从下标为零的元素开始,按升序初始化数组元素。数组初始值设定项中所包含的表达式的数组确定正在创建的数组实例的长度。
对于多维数组,数组初始值设定项必须具有与数组维数相同的嵌套级别。最外面的嵌套级别对应于最左边的维度,而最里面的嵌套级别对应最右边的维度。数组各维度的长度由数组初始值设定项中相应嵌套级别内的元素数目确定。对于每个嵌套的数组初始值设定项,元素的数目必须与同一级别的其他数组初始值设定项所包含的元素数相同。比如:
当数组创建表达式同时包含显式维度长度和一个数组初始值设定项时,长度必须时常熟表达式,并且各嵌套级别的元素数目必须与对应的维度长度匹配。比如: