数组Arrays

数组是一种数据结构,它包含多个通过计算索引访问的变量。An array is a data structure that contains a number of variables which are accessed through computed indices. 数组中的变量(亦称为数组的元素)均为同一种类型,我们将这种类型称为数组的元素类型。The variables contained in an array, also called the elements of the array, are all of the same type, and this type is called the element type of the array.

数组具有确定与每个数组元素关联的索引数的排名。An array has a rank which determines the number of indices associated with each array element. 数组的秩也称为数组的维数。The rank of an array is also referred to as the dimensions of the array. 秩为 one 的数组称为 *单维数组 _。An array with a rank of one is called a *single-dimensional array _. 秩大于1的数组称为 _ 多维数组 *。An array with a rank greater than one is called a _*multi-dimensional array**. 特定大小的多维数组通常称为二维数组,这是三维数组等。Specific sized multi-dimensional arrays are often referred to as two-dimensional arrays, three-dimensional arrays, and so on.

数组的每个维度都有一个关联的长度,该长度是大于或等于零的整数。Each dimension of an array has an associated length which is an integral number greater than or equal to zero. 维度长度不是数组类型的一部分,而是在运行时创建数组类型的实例时建立的。The dimension lengths are not part of the type of the array, but rather are established when an instance of the array type is created at run-time. 维度的长度决定了该维度的有效索引范围:对于长度为的维度 N ,索引范围可以从 0 到包含的范围 N - 1The length of a dimension determines the valid range of indices for that dimension: For a dimension of length N, indices can range from 0 to N - 1 inclusive. 数组中元素的总数为数组中每个维度的长度的乘积。The total number of elements in an array is the product of the lengths of each dimension in the array. 如果数组的一个或多个维度的长度为零,则将此数组称为空。If one or more of the dimensions of an array have a length of zero, the array is said to be empty.

数组的元素类型可以是任意类型(包括数组类型)。The element type of an array can be any type, including an array type.

数组类型Array types

数组类型以 non_array_type ,后跟一个或多个 rank_specifier s:An array type is written as a non_array_type followed by one or more rank_specifier s:

array_type
    : non_array_type rank_specifier+
    ;

non_array_type
    : type
    ;

rank_specifier
    : '[' dim_separator* ']'
    ;

dim_separator
    : ','
    ;

Non_array_type 是自身不是 array_type 的任何 类型A non_array_type is any type that is not itself an array_type.

数组类型的秩由 array_type 中最左边的 rank_specifier 提供: rank_specifier 指示数组是一个数组,该数组的秩为1,加上 , rank_specifier 中的 "" 标记数。The rank of an array type is given by the leftmost rank_specifier in the array_type: A rank_specifier indicates that the array is an array with a rank of one plus the number of "," tokens in the rank_specifier.

数组类型的元素类型是通过删除最左边的 rank_specifier 得出的类型:The element type of an array type is the type that results from deleting the leftmost rank_specifier:

  • 窗体的数组类型 T[R] 是具有 rank R 和非数组元素类型的数组 TAn array type of the form T[R] is an array with rank R and a non-array element type T.
  • 窗体的数组类型 T[R][R1]...[Rn] 是具有秩 R 和元素类型的数组 T[R1]...[Rn]An array type of the form T[R][R1]...[Rn] is an array with rank R and an element type T[R1]...[Rn].

实际上,在最后一个非数组元素类型之前, rank_specifier 从左到右读取。In effect, the rank_specifier s are read from left to right before the final non-array element type. 类型是的二维数组的 int[][,,][,] 一维数组,它是的二维数组 intThe type int[][,,][,] is a single-dimensional array of three-dimensional arrays of two-dimensional arrays of int.

在运行时,数组类型的值可以是 null 或对该数组类型的实例的引用。At run-time, a value of an array type can be null or a reference to an instance of that array type.

System.object 类型The System.Array type

类型 System.Array 是所有数组类型的抽象基类型。The type System.Array is the abstract base type of all array types. 隐式引用转换 () 存在于从任何数组类型到的 隐式引用 转换 System.Array ,并 (显式) 引用 转换显式引用转换 System.Array 为任意数组类型。An implicit reference conversion (Implicit reference conversions) exists from any array type to System.Array, and an explicit reference conversion (Explicit reference conversions) exists from System.Array to any array type. 请注意, System.Array 并不是 array_typeNote that System.Array is not itself an array_type. 相反,它是派生所有 array_typeclass_typeRather, it is a class_type from which all array_type s are derived.

在运行时,类型的值 System.Array 可以是或对 null 任何数组类型的实例的引用。At run-time, a value of type System.Array can be null or a reference to an instance of any array type.

数组和泛型 IList 接口Arrays and the generic IList interface

一维数组 T[] System.Collections.Generic.IList<T> IList<T> 为 short) 及其基接口实现了接口 (。A one-dimensional array T[] implements the interface System.Collections.Generic.IList<T> (IList<T> for short) and its base interfaces. 相应地,存在从 T[] 到及其基接口的隐式转换 IList<T>Accordingly, there is an implicit conversion from T[] to IList<T> and its base interfaces. 此外,如果存在从到的隐式引用转换 ST S[] 并实现了从到的隐式 IList<T> 引用转换 S[] IList<T> ,并且其基接口) (隐式引用转换In addition, if there is an implicit reference conversion from S to T then S[] implements IList<T> and there is an implicit reference conversion from S[] to IList<T> and its base interfaces (Implicit reference conversions). 如果存在从到的显式引用转换,则从到的显式引用转换 S T S[] IList<T> ,并且其基接口 (显式引用转换) 。If there is an explicit reference conversion from S to T then there is an explicit reference conversion from S[] to IList<T> and its base interfaces (Explicit reference conversions). 例如:For example:

using System.Collections.Generic;

class Test
{
    static void Main() {
        string[] sa = new string[5];
        object[] oa1 = new object[5];
        object[] oa2 = sa;

        IList<string> lst1 = sa;                    // Ok
        IList<string> lst2 = oa1;                   // Error, cast needed
        IList<object> lst3 = sa;                    // Ok
        IList<object> lst4 = oa1;                   // Ok

        IList<string> lst5 = (IList<string>)oa1;    // Exception
        IList<string> lst6 = (IList<string>)oa2;    // Ok
    }
}

赋值 lst2 = oa1 会生成编译时错误,因为从到的转换 object[] IList<string> 是显式转换,而不是隐式转换。The assignment lst2 = oa1 generates a compile-time error since the conversion from object[] to IList<string> is an explicit conversion, not implicit. 强制转换 (IList<string>)oa1 会导致在运行时引发异常 oa1 ,因为引用的是 object[] 而不是 string[]The cast (IList<string>)oa1 will cause an exception to be thrown at run-time since oa1 references an object[] and not a string[]. 但强制转换 (IList<string>)oa2 不会导致引发异常,因为 oa2 引用了 string[]However the cast (IList<string>)oa2 will not cause an exception to be thrown since oa2 references a string[].

无论何时存在从到的隐式或显式引用转换 S[] IList<T> ,都有一个从 IList<T> 和其基接口到 S[] (显式引用转换) 的显式引用转换。Whenever there is an implicit or explicit reference conversion from S[] to IList<T>, there is also an explicit reference conversion from IList<T> and its base interfaces to S[] (Explicit reference conversions).

当数组类型 S[] 实现时 IList<T> ,实现的接口的某些成员可能会引发异常。When an array type S[] implements IList<T>, some of the members of the implemented interface may throw exceptions. 接口的实现的精确行为超出了本规范的范围。The precise behavior of the implementation of the interface is beyond the scope of this specification.

数组创建Array creation

数组实例是通过 array_creation_expression s (数组创建表达式 创建的,) 或通过包含 array_initializer (数组初始值设定项 的字段或局部变量声明来创建。Array instances are created by array_creation_expression s (Array creation expressions) or by field or local variable declarations that include an array_initializer (Array initializers).

创建数组实例时,将建立每个维度的秩和长度,并在实例的整个生存期内保持不变。When an array instance is created, the rank and length of each dimension are established and then remain constant for the entire lifetime of the instance. 换句话说,不能更改现有数组实例的排名,也不能调整其维度的大小。In other words, it is not possible to change the rank of an existing array instance, nor is it possible to resize its dimensions.

数组实例始终为数组类型。An array instance is always of an array type. System.Array类型是无法实例化的抽象类型。The System.Array type is an abstract type that cannot be instantiated.

array_creation_expression 创建的数组元素始终初始化为其默认值) (默认值Elements of arrays created by array_creation_expression s are always initialized to their default value (Default values).

数组元素访问Array element access

数组元素是使用窗体的 (数组访问) element_access 表达式访问的 A[I1, I2, ..., In] ,其中, A 是数组类型的表达式,每个表达式 Ix 都是类型、、、或的表达式, int uint long ulong 可以隐式转换为这些类型中的一个或多个。Array elements are accessed using element_access expressions (Array access) of the form A[I1, I2, ..., In], where A is an expression of an array type and each Ix is an expression of type int, uint, long, ulong, or can be implicitly converted to one or more of these types. 数组元素访问的结果是一个变量,即索引选择的数组元素。The result of an array element access is a variable, namely the array element selected by the indices.

可以使用 foreach (foreach 语句) 的语句来枚举数组的元素。The elements of an array can be enumerated using a foreach statement (The foreach statement).

数组成员Array members

每个数组类型都继承类型所声明的成员 System.ArrayEvery array type inherits the members declared by the System.Array type.

数组协方差Array covariance

对于任意两个 reference_type s A 和,如果隐式引用转换 B (隐式 引用转换) 或显式引用转换 (显式 引用转换) 存在于中 A B ,则相同的引用转换也是从数组类型 A[R] 到数组类型 B[R] ,其中 R 是所有给定的 rank_specifier (但对于这两个数组类型) 是相同的。For any two reference_type s A and B, if an implicit reference conversion (Implicit reference conversions) or explicit reference conversion (Explicit reference conversions) exists from A to B, then the same reference conversion also exists from the array type A[R] to the array type B[R], where R is any given rank_specifier (but the same for both array types). 此关系称为 数组协方差This relationship is known as array covariance. 具体说来,数组协方差意味着数组类型的值 A[R] 实际上可以是对数组类型的实例的引用 B[R] ,前提是从到存在隐式引用转换 B AArray covariance in particular means that a value of an array type A[R] may actually be a reference to an instance of an array type B[R], provided an implicit reference conversion exists from B to A.

由于数组协变,对引用类型数组的元素的赋值包含运行时检查,这可确保分配给数组元素的值实际上是 (简单赋值) 的允许类型。Because of array covariance, assignments to elements of reference type arrays include a run-time check which ensures that the value being assigned to the array element is actually of a permitted type (Simple assignment). 例如:For example:

class Test
{
    static void Fill(object[] array, int index, int count, object value) {
        for (int i = index; i < index + count; i++) array[i] = value;
    }

    static void Main() {
        string[] strings = new string[100];
        Fill(strings, 0, 100, "Undefined");
        Fill(strings, 0, 10, null);
        Fill(strings, 90, 10, 0);
    }
}

array[i]方法中对的赋值 Fill 隐式包含运行时检查,该检查可确保所引用的对象 valuenull 或与实际元素类型兼容的实例 arrayThe assignment to array[i] in the Fill method implicitly includes a run-time check which ensures that the object referenced by value is either null or an instance that is compatible with the actual element type of array. 在中 Main ,的前两个调用 Fill 成功,但第三个调用导致在 System.ArrayTypeMismatchException 执行第一次分配到时引发 array[i]In Main, the first two invocations of Fill succeed, but the third invocation causes a System.ArrayTypeMismatchException to be thrown upon executing the first assignment to array[i]. 发生此异常的原因是装箱 int 无法存储在 string 数组中。The exception occurs because a boxed int cannot be stored in a string array.

具体说来,数组协方差不会扩展到 value_type 的数组。Array covariance specifically does not extend to arrays of value_type s. 例如,不存在允许 int[] 将视为的转换 object[]For example, no conversion exists that permits an int[] to be treated as an object[].

数组初始值设定项Array initializers

可以在字段声明中指定数组初始值设定项, (字段) 、局部变量声明 (局部变量 声明) 和数组创建表达式 (数组创建表达式) :Array initializers may be specified in field declarations (Fields), local variable declarations (Local variable declarations), and array creation expressions (Array creation expressions):

array_initializer
    : '{' variable_initializer_list? '}'
    | '{' variable_initializer_list ',' '}'
    ;

variable_initializer_list
    : variable_initializer (',' variable_initializer)*
    ;

variable_initializer
    : expression
    | array_initializer
    ;

数组初始值设定项由变量初始值设定项序列组成,括在 " { " 和 "" 标记中,并用 } " , " 标记分隔。An array initializer consists of a sequence of variable initializers, enclosed by "{" and "}" tokens and separated by "," tokens. 每个变量初始值设定项是一个表达式,如果是多维数组的嵌套数组初始值设定项,则为。Each variable initializer is an expression or, in the case of a multi-dimensional array, a nested array initializer.

使用数组初始值设定项的上下文决定了要初始化的数组的类型。The context in which an array initializer is used determines the type of the array being initialized. 在数组创建表达式中,数组类型紧靠在初始值设定项之前,或从数组初始值设定项的表达式中推断。In an array creation expression, the array type immediately precedes the initializer, or is inferred from the expressions in the array initializer. 在字段或变量声明中,数组类型是要声明的字段或变量的类型。In a field or variable declaration, the array type is the type of the field or variable being declared. 当在字段或变量声明中使用数组初始值设定项时,如:When an array initializer is used in a field or variable declaration, such as:

int[] a = {0, 2, 4, 6, 8};

它只是等效数组创建表达式的简写形式:it is simply shorthand for an equivalent array creation expression:

int[] a = new int[] {0, 2, 4, 6, 8};

对于一维数组,数组初始值设定项必须包含一系列表达式,这些表达式与数组的元素类型兼容。For a single-dimensional array, the array initializer must consist of a sequence of expressions that are assignment compatible with the element type of the array. 表达式以递增顺序初始化数组元素,从索引零处的元素开始。The expressions initialize array elements in increasing order, starting with the element at index zero. 数组初始值设定项中的表达式数决定了要创建的数组实例的长度。The number of expressions in the array initializer determines the length of the array instance being created. 例如,上面的数组初始值设定项创建一个 int[] 长度为5的实例,然后使用以下值初始化该实例:For example, the array initializer above creates an int[] instance of length 5 and then initializes the instance with the following values:

a[0] = 0; a[1] = 2; a[2] = 4; a[3] = 6; a[4] = 8;

对于多维数组,数组初始值设定项必须具有与数组中的维数一样多的嵌套级别。For a multi-dimensional array, the array initializer must have as many levels of nesting as there are dimensions in the array. 最外层嵌套级别对应于最左边的维度,最内层的嵌套级别对应于最右边的维度。The outermost nesting level corresponds to the leftmost dimension and the innermost nesting level corresponds to the rightmost dimension. 数组的每个维度的长度由数组初始值设定项中相应嵌套级别的元素数决定。The length of each dimension of the array is determined by the number of elements at the corresponding nesting level in the array initializer. 对于每个嵌套的数组初始值设定项,元素数必须与同一级别的其他数组初始值设定项相同。For each nested array initializer, the number of elements must be the same as the other array initializers at the same level. 示例:The example:

int[,] b = {{0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}};

为最左侧的维度创建长度为5的二维数组,并为最右边的维度创建两个长度的长度:creates a two-dimensional array with a length of five for the leftmost dimension and a length of two for the rightmost dimension:

int[,] b = new int[5, 2];

然后,用以下值初始化数组实例:and then initializes the array instance with the following values:

b[0, 0] = 0; b[0, 1] = 1;
b[1, 0] = 2; b[1, 1] = 3;
b[2, 0] = 4; b[2, 1] = 5;
b[3, 0] = 6; b[3, 1] = 7;
b[4, 0] = 8; b[4, 1] = 9;

如果向右端指定了长度为零的维度,则假定后续维度的长度也为零。If a dimension other than the rightmost is given with length zero, the subsequent dimensions are assumed to also have length zero. 示例:The example:

int[,] c = {};

创建一个二维数组,其长度为零,最左侧和最右边的维度:creates a two-dimensional array with a length of zero for both the leftmost and the rightmost dimension:

int[,] c = new int[0, 0];

当数组创建表达式同时包含显式维度长度和数组初始值设定项时,长度必须为常量表达式,并且每个嵌套级别的元素数必须与相应的维度长度匹配。When an array creation expression includes both explicit dimension lengths and an array initializer, the lengths must be constant expressions and the number of elements at each nesting level must match the corresponding dimension length. 下面是一些示例:Here are some examples:

int i = 3;
int[] x = new int[3] {0, 1, 2};        // OK
int[] y = new int[i] {0, 1, 2};        // Error, i not a constant
int[] z = new int[3] {0, 1, 2, 3};     // Error, length/initializer mismatch

此处的初始值设定项 y 会导致编译时错误,因为维度长度表达式不是常量,并且的初始值设定项会 z 导致编译时错误,因为初始值设定项中的元素长度和元素数不一致。Here, the initializer for y results in a compile-time error because the dimension length expression is not a constant, and the initializer for z results in a compile-time error because the length and the number of elements in the initializer do not agree.