第十六章 数组

目录:

16.1 初始化数组

16.2 数组转型

16.3 所有数组都隐式派生自System.Array

16.4 所有数组都隐式实现IEnumerable和IList

16.5 数组的传递和返回

16.7 数组的内部工作原理

16.8 不安全的数组访问和固定大小的数组

数组是允许将多个数组项作为集合来处理的机制。CLR支持一维,多维和交错数组(数组构成的数组)。所有数组类型都隐式的从System。Array抽象类派生,后者又派生自System.Object。这意味着数组始终是引用类型,是在托管堆上分配的。在应用程序的变量或字段中,包含的是对数组的引用,而不是包含数组本身的元素。

为了符合“公共语言规范”的要求,所有数组都必须是0基数组(最小索引为0)。每个数组都关联了一些额外的开销信息。这些信息包括数组的秩,数组每一维的下限(几乎总是0)和每一维长度。开销信息还包含数组的元素类型。

16.1 初始化数组

大括号中的以逗号分隔的数据项称为数组初始化器。每个数据项都可以使一个任意复杂度的表达式;在多维数组的情况下,则可以使一个嵌套的数组初始化器。 

16.2 数组转型

 Array.Copy方法:

将值类型的元素装箱为引用类型的元素。

将引用类型的元素拆箱为值类型元素。

加宽CLR基元值类型。

在两个数组之间复制时,如果仅从数组类型证明不了两者的兼容性,就根据需要对元素进行向下类型转换。

 

将数组从一种类型转换为另一种类型。成为-数组协变性

16.3 所有数组都隐式派生自System.Array

 声明一个数组,CLR会自动为AppDomain创建类型。改类型隐士派生自System.Array类型。

16.4 所有数组都隐式实现IEnumerable和IList

16.5 数组的传递和返回

 数组作为实参传递给方法时,实际传递的是对该数组的引用。因此被调用的方法能修改数组中的元素。如果不想被修改,必须生成数组的拷贝并将拷贝传给方法。

有的方法返回对数组的引用。如果方法返回的是对字段所维护的一个内部数组的引用,就必须决定是否想让改方法的调用者直接访问这个数组及元素。方法应该构造一个新数组,并调用Array.Copy返回对新数组的引用。

16.6 创建下限非零的数组

调用数组的静态CreatInstance方法来动态创建自己的数组。

16.7 数组的内部工作原理

 CLR内部支持两种不同的数组:

下限为0的一维数组。这些数组有时称为SZ(一维0基)数组或向量。

下限未知的一维或多维数组。

不安全数组访问技术不足:

相较于其他技术,处理数组元素的代码更复杂,不容易读和写,因为要使用C#fixed语句,要执行内存地址计算。

计算过程中出错,可能访问到不属于数组的内存。这会造成计算错误,损坏内存数据,破坏类型安全性,并可能造成安全漏洞。

因为这些潜在的问题,CLR禁止在降低了安全级别的环境中运行不安全代码。

16.8 不安全的数组访问和固定大小的数组

 不安全代码允许访问:

堆上的托管数组对象中的元素

非托管堆上的数组中的元素

线程栈上的数组中的元素

如果性能是首要目标,请避免在堆上分配托管的数组对象。相反,在线程栈上分配数组。

由于数组是引用类型,所以结构中定义的数组字段实际只是指向数组的指针或引用。数组本身在结构的内部的外部。也可以直接嵌入结构:

类型必须是结构(值类型);不能在类中嵌入数组。

字段或其定义结构必须用usafe关键字标记。

数组字段必须用fixed关键字标记

数组必须是一维0基数组。

要和非托管代码进行互操作,而且非托管数据结构也有一个内联数组,就特别适合使用内联得数组。但内联数组也能用于其他地方。

posted @ 2019-01-15 08:26  郭大大大  阅读(148)  评论(0编辑  收藏  举报