Заметка
Доступ к этой странице требует авторизации. Вы можете попробовать войти в систему или изменить каталог.
Доступ к этой странице требует авторизации. Вы можете попробовать сменить директорию.
17.1 Общие
Массив — это структура данных, содержащая несколько переменных, доступ к которым осуществляется по вычисляемым индексам. Переменные, содержащиеся в массиве, называются каждым элементом этого массива. Все элементы этого массива имеют одинаковый тип, и этот тип называется типом элемента массива.
Массив имеет ранг, определяющий количество индексов, связанных с каждым элементом массива. Ранг массива также называется измерениями массива. Массив с рангом одного называется одномерным массивом. Массив с рангом больше одного называется многомерным массивом. Многомерные массивы определенного размера часто называются двумерными массивами, трехмерные массивы и т. д. Каждое измерение массива имеет связанную длину, которая является целочисленным числом, превышающим или равным нулю. Длина измерения не является частью типа массива, а устанавливается при создании экземпляра типа массива во время выполнения. Длина измерения определяет допустимый диапазон индексов для этого измерения: для измерения длины Nиндексы могут варьироваться 0 от N – 1 до инклюзивного. Общее количество элементов в массиве — это произведение длины каждого измерения в массиве. Если один или несколько измерений массива имеют длину нулю, массив считается пустым.
Тип элемента массива может быть типом массива (§17.2.1). Такие массивы массивов отличаются от многомерных массивов и могут использоваться для представления "многомерных массивов".
Пример:
int[][] pascals = { new int[] {1}, new int[] {1, 1}, new int[] {1, 2, 1}, new int[] {1, 3, 3, 1} };пример конца
Каждый тип массива является ссылочным типом (§8.2). Тип элемента массива может быть любым типом, включая типы значений и типы массивов.
Типы массивов 17.2
17.2.1 Общие
Грамматические типы массивов предоставляются в §8.2.1.
Тип массива записывается как non_array_type за которым следует один или несколько rank_specifier.
Non_array_type — это любой тип, который не является array_type.
Ранг типа массива присваивается самым левым rank_specifier в array_type: rank_specifier указывает, что массив является массивом с рангом одного плюс число маркеров "," в rank_specifier.
Тип элемента типа массива — это тип, который приводит к удалению самого левого rank_specifier:
- Тип массива формы
T[R]— это массив с рангомRи типомTэлемента, отличного от массива. - Тип массива формы
T[R][R₁]...[Rₓ]— это массив с рангомRи типомT[R₁]...[Rₓ]элемента.
В действительности rank_specifierсчитываются слева направо до конечного типа элемента, отличного от массива.
Пример: тип является
T[][,,][,]одномерным массивом трехмерных массивов двухмерных массивовint. пример конца
Во время выполнения значение типа массива может быть null или ссылкой на экземпляр этого типа массива.
Примечание. В соответствии с правилами §17.6 значение также может быть ссылкой на ковариантный тип массива. конечная заметка
17.2.2 Тип System.Array
System.Array Тип является абстрактным базовым типом всех типов массивов. Неявное преобразование ссылок (§10.2.8) существует из любого типа массива в System.Array любой тип интерфейса и любого типа интерфейса, реализованного с помощью System.Array. Явное преобразование ссылок (§10.3.5) существует из System.Array любого типа интерфейса, реализуемого любым типом System.Array массива.
System.Array не является самой array_type. Скорее, это class_type , от которого производны все array_type.
Во время выполнения значение типа System.Array может быть null или ссылка на экземпляр любого типа массива.
Массивы 17.2.3 и универсальные интерфейсы коллекции
Одномерный массив T[] реализует интерфейс System.Collections.Generic.IList<T> (IList<T> для короткого) и его базовые интерфейсы. Соответственно, происходит неявное преобразование из T[]IList<T> и его базовых интерфейсов. Кроме того, если есть неявное преобразование ссылок, S оттуда T реализуется S[] и происходит неявное преобразование ссылок из IList<T>S[] и его базовых интерфейсов (IList<T>). Если есть явное преобразование S ссылок на то есть явное преобразование ссылок из TS[] и его базовых интерфейсов (IList<T>).
Аналогичным образом одномерный массив T[] также реализует интерфейс System.Collections.Generic.IReadOnlyList<T> (IReadOnlyList<T> для краткого) и его базовых интерфейсов. Соответственно, происходит неявное преобразование из T[]IReadOnlyList<T> и его базовых интерфейсов. Кроме того, если есть неявное преобразование ссылок, S оттуда T реализуется S[] и происходит неявное преобразование ссылок из IReadOnlyList<T>S[] и его базовых интерфейсов (IReadOnlyList<T>). Если есть явное преобразование S ссылок на то есть явное преобразование ссылок из TS[] и его базовых интерфейсов (IReadOnlyList<T>).
Пример: например:
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 IReadOnlyList<string> lst7 = sa; // Ok IReadOnlyList<string> lst8 = oa1; // Error, cast needed IReadOnlyList<object> lst9 = sa; // Ok IReadOnlyList<object> lst10 = oa1; // Ok IReadOnlyList<string> lst11 = (IReadOnlyList<string>)oa1; // Exception IReadOnlyList<string> lst12 = (IReadOnlyList<string>)oa2; // Ok } }Назначение
lst2 = oa1создает ошибку во время компиляции, так как преобразование изobject[]IList<string>неявного преобразования является явным преобразованием. Приведение(IList<string>)oa1приведет к возникновению исключения во время выполнения, так какoa1ссылки на нееobject[]string[]и не являются. Однако приведение (IList<string>)oa2не приведет к возникновению исключения, так какoa2ссылки на нееstring[]возникают.пример конца
Всякий раз, когда происходит неявное или явное преобразование ссылок в S[]IList<T>, также имеется явное преобразование ссылок из IList<T> и его базовых интерфейсов S[] в (§10.3.5).
При реализации S[]типа IList<T> массива некоторые члены реализованного интерфейса могут вызывать исключения. Точное поведение реализации интерфейса выходит за рамки этой спецификации.
Создание массива 17.3
Экземпляры массива создаются array_creation_expressions (§12.8.17.4) или по полям или локальным объявлениям переменных, которые включают array_initializer (§17.7). Экземпляры массива также можно создавать неявно в рамках оценки списка аргументов, включающего массив параметров (§15.6.2.4).
При создании экземпляра массива устанавливается ранг и длина каждого измерения, а затем остается константой в течение всего времени существования экземпляра. Другими словами, невозможно изменить ранг существующего экземпляра массива и изменить его размеры.
Экземпляр массива всегда имеет тип массива. Тип System.Array является абстрактным типом, который не может быть создан.
Элементы массивов, созданных array_creation_expressions, всегда инициализированы в значение по умолчанию (§9.3).
Доступ к элементу массива 17.4
Доступ к элементам массива осуществляется с помощью варианта доступа к массивувыражений element_access (§12.8.12.2) формыA[I₁, I₂, ..., Iₓ], где A является выражением типа Iₑintмассива , uintlongulongили может быть неявно преобразовано в один или несколько этих типов. Результатом доступа к массиву является переменная ссылка (§9.5) на элемент массива, выбранный индексами.
Элементы массива одномерных массивов также могут быть доступны с помощью выражения доступа к массиву, где единственный индекс, I₁является выражением типа Index, Rangeили может быть неявно преобразован в один или оба этих типа. Если I₁ тип Indexили неявно преобразован в этот тип, результат доступа к массиву является переменной ссылкой на элемент массива, выбранный значением индекса. Если I₁ имеет тип Rangeили был неявно преобразован в этот тип, результат доступа к элементу представляет собой новый массив, сформированный из мелкой копии элементов массива с индексами в элементе Range, поддерживая порядок элементов.
Элементы массива можно перечислить с помощью foreach инструкции (§13.9.5).
Элементы массива 17.5
Каждый тип массива наследует элементы, объявленные типом System.Array .
Ковариация массива 17.6
Для всех двух reference_typeи AB , если неявное преобразование ссылок (§10.2.8) или явное преобразование ссылок (§10.3.5) существует от AB, то такое же преобразование ссылок также существует из типа массива в тип A[R]B[R]массива, где R любой заданный rank_specifier (но одинаковый для обоих типов массивов). Эта связь называется ковариантностью массива. В частности, ковариация массива означает, что значение типа массива может быть ссылкой на экземпляр типа A[R]B[R]массива, если неявное преобразование ссылок существует от BA.
Из-за ковариации массива назначения для элементов массивов ссылочных типов включают проверку времени выполнения, которая гарантирует, что значение, назначенное элементу массива, фактически является разрешенным типом (§12.23.2).
Пример:
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это ссылка или ссылка на объект типа, совместимого с фактическим типомarrayэлемента. ВMain, первые два вызоваFillуспешно, но третий вызов вызываетSystem.ArrayTypeMismatchExceptionисключение при выполнении первого заданияarray[i]. Исключение возникает, так как прямоугольныйintне может храниться в массивеstring.пример конца
Ковариация массива специально не распространяется на массивы value_types. Например, преобразование не существует, позволяющее int[] рассматривать его как .object[]
Инициализаторы массива 17.7
Инициализаторы массива могут быть указаны в объявлениях полей (§15.5), объявлениях локальных переменных (§13.6.2) и выражениях создания массива (§12.8.17.4):
array_initializer
: '{' variable_initializer_list? '}'
| '{' variable_initializer_list ',' '}'
;
variable_initializer_list
: variable_initializer (',' variable_initializer)*
;
variable_initializer
: expression
| array_initializer
;
Инициализатор массива состоит из последовательности инициализаторов переменных, заключенных в маркеры "{" и "}" и разделенных, "" маркерами. Каждый инициализатор переменных является выражением или в случае многомерного массива инициализатором вложенного массива.
Контекст, в котором используется инициализатор массива, определяет тип инициализированного массива. В выражении создания массива тип массива сразу же предшествует инициализатору или выводится из выражений в инициализаторе массива. В объявлении поля или переменной тип массива является типом объявленного поля или переменной. Когда инициализатор массива используется в объявлении поля или переменной,
int[] a = {0, 2, 4, 6, 8};
Это просто сокращено для эквивалентного выражения создания массива:
int[] a = new int[] {0, 2, 4, 6, 8};
Для одномерного массива инициализатор массива должен состоять из последовательности выражений, каждый из которых имеет неявное преобразование в тип элемента массива (§10.2). Выражения инициализируют элементы массива в растущем порядке, начиная с элемента с нуля индекса. Количество выражений в инициализаторе массива определяет длину создаваемого экземпляра массива.
Пример. Инициализатор массива, приведенный выше, создает
int[]экземпляр длиной 5, а затем инициализирует экземпляр со следующими значениями:a[0] = 0; a[1] = 2; a[2] = 4; a[3] = 6; a[4] = 8;пример конца
Для многомерного массива инициализатор массива должен иметь столько уровней вложения, сколько размеров в массиве. Самый внешний уровень вложения соответствует самому левому измерению, а самый внутренний уровень вложения соответствует самому правому измерению. Длина каждого измерения массива определяется числом элементов на соответствующем уровне вложения в инициализаторе массива. Для каждого инициализатора вложенного массива число элементов должно совпадать с другими инициализаторами массива на том же уровне.
Пример: пример:
int[,] b = {{0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}};создает двухмерный массив длиной 5 для самого левого измерения и длиной двух для самого правого измерения:
int[,] b = new int[5, 2];а затем инициализирует экземпляр массива со следующими значениями:
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;пример конца
Если измерение, отличное от самого правого, присваивается ноль длины, то последующие измерения также имеют нуль длины.
Пример:
int[,] c = {};создает двухмерный массив с длиной нуля как для самого левого, так и для самого правого измерения:
int[,] c = new int[0, 0];пример конца
Если выражение создания массива включает как явные длины измерений, так и инициализатор массива, длина должна быть константными выражениями, а количество элементов на каждом уровне вложения должно соответствовать соответствующей длине измерения.
Пример. Ниже приведены некоторые примеры.
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результатов в результате ошибки во время компиляции, так как длина и количество элементов в инициализаторе не согласны.пример конца
Примечание. C# позволяет запятую в конце array_initializer. Этот синтаксис обеспечивает гибкость при добавлении или удалении элементов из такого списка и упрощении создания таких списков компьютеров. конечная заметка
ECMA C# draft specification