《CLR via C#》 数组
CLR支持一维、多维和交错数组。所有数组都隐式地从System.Array
抽象类派生,后者又派生自System.Object
。这意味着数组始终是引用类型,从托管堆分配。
一维数组
1int[] arr; // 声明一个数组引用
2arr = new int[100]; // 创建含有100个int的数组,并全部初始化为0
实际上,除了数组元素,数组对象占据的内存块还包含一个类型对象指针、一个同步块索引和一些额外的成员。
注意
应尽可能的使用一维0基数组。因为其性能是最佳的,可以使用一些特殊的IL指令来处理。
多维数组
1double[,] darr = new double[10, 20]; // 二维数组
2string[,,] sarr = new string[5, 3, 10]; // 三维数组
交错数组
交错数组:数组构成的数组。0基一维交错数组的性能和普通向量一样好。不过访问交错数组的元素意味着必须进行两次或更多此访问。
1int[][] arr = new int[3][]; // 创建由多个int数组构成的一维数组
2arr[0] = new int[10]; // arr[0]引用一个含有10个int实例的数组
3arr[1] = new int[20]; // arr[1]引用一个含有20个int实例的数组
4arr[2] = new int[30]; // arr[2]引用一个含有30个int实例的数组
数组初始化
1// 大括号中以逗号分隔的数据项称为数组初始化器
2String[] names = new String[] {"A", "B"};
3// 隐式类型数组。
4var kids = new[] {new {Name="A"}, new {Name="B"} };
数组转型
CLR不允许将值类型元素的数组转型为其它任何类型。(不过可用Array.Copy
方法创建新数组并在其中填充元素来模拟这种效果)
1int[] iarr = new int[5];
2// object[] oarr = (object[]) iarr; // 编译报错
3
4// 创建一个新数组,使用Array.Copy将源数组中的每个元素转型为目标数组中的元素类型,并把它们复制过去。(Array.Copy是浅拷贝)
5object[] oarr = new object[iarr.Length];
6Array.Copy(iarr, oarr, iarr.Length);
注意
可用System.Buffer
的BlockCopy
方法将元素复制到另一个数组,它比Array.Copy
方法块,但只支持基元类型。
数组的隐式继承
- 所有数组都隐式派生自
System.Array
- 所有数组都隐式实现
IEnumerable
,ICollection
,IList
创建一维0基数数组类型时,CLR自动使数组类型实现IEnumerable<T>
,ICollection<T>
和IList<T>
。同时,还为数组类型的所有基类型实现这三个接口,必须是引用类型。
1public class A {}
2public class B : A {}
3B[] b = new B[2]; // 会为A[]和B[]自动实现其三个接口
注意
数组作为实参传递给方法时,实际传递的是数组的引用
创建下限非零开始的数组
利用数组的静态CreateInstance
方法来动态创建数组。CreateInstance
为数组分配内存,将参数信息保存到数组的内存块开销部分,然后返回对该数组的引用。如果数组为多维数组。可以把数组引用转型为ElementType[]
变量来对数组元素访问。如果只有一维,要求必须用Array.GetValue
和Array.SetValue
访问数组
1// 创建二维数组[2005...2009][1...4]
2int[] lowerBounds = {2005, 1};
3int[] lengths = {5, 4};
4int[,] arr = (int[,]) Array.CreateInstance(typeof(int), lengths, lowerBounds);
数组的内部工作原理
CLR内部实际支持两种不同的数组
- 下限从0开始的一维数组。
- 下限开始未知的一维或多维数组。
注意
访问一维0基数组的元素比访问非0基一维或多维数组的元素稍快。如果很关心新能可以用交错数组来代替矩阵数组。