배열 17개
17.1 일반
배열은 계산된 인덱스를 통해 액세스되는 여러 변수를 포함하는 데이터 구조입니다. 배열에 포함된 변수, 즉 배열의 요소라고도 하는 배열은 모두 같은 형식이며, 이 형식을 배열의 요소 형식이라고 합니다.
배열에는 각 배열 요소와 연결된 인덱스 수를 결정하는 순위가 있습니다. 배열의 순위를 배열의 차원이라고도 합니다. 순위가 1인 배열을 1차원 배열이라고 합니다. 순위가 1보다 큰 배열을 다차원 배열이라고 합니다. 특정 크기의 다차원 배열은 종종 2차원 배열, 3차원 배열 등이라고 합니다. 배열의 각 차원에는 0보다 크거나 같은 정수인 연결된 길이가 있습니다. 차원 길이는 배열 형식의 일부가 아니라 런타임에 배열 형식의 인스턴스를 만들 때 설정됩니다. 차원의 길이에 따라 해당 차원의 유효한 인덱스 범위가 결정됩니다. 길이 N
차원의 경우 인덱스의 범위는 포함 범위일 0
N – 1
수 있습니다. 배열의 총 요소 수는 배열의 각 차원 길이에 대한 곱입니다. 배열의 차원 중 하나 이상의 길이가 0인 경우 배열은 비어 있다고 합니다.
배열의 요소 형식 자체는 배열 형식(§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에서 제공됩니다.
배열 형식은 하나 이상의 rank_specifier 뒤에 non_array_type 기록됩니다.
non_array_type array_type 아닌 모든 형식입니다.
배열 형식의 순위는 array_type 맨 왼쪽 rank_specifier 의해 지정됩니다. rank_specifier 배열이 1의 순위와 rank_specifier ",
" 토큰 수를 더한 배열임을 나타냅니다.
배열 형식의 요소 형식은 가장 왼쪽 rank_specifier 삭제한 결과인 형식입니다.
- 폼
T[R]
의 배열 형식은 순위R
가 있는 배열과 배열이 아닌 요소 형식입니다T
. - 폼
T[R][R₁]...[Rₓ]
의 배열 형식은 순위R
가 있는 배열과 요소 형식T[R₁]...[Rₓ]
입니다.
실제로 rank_specifier마지막 비 배열 요소 형식 전에 왼쪽에서 오른쪽으로 읽습니다.
예: 형식
T[][,,][,]
은 2차원 배열의 3차원 배열로 구성된 1차원 배열입니다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 아닙니다. 오히려 모든 array_type 파생되는 class_type.
런타임에 형식 값은 배열 형식 System.Array
의 인스턴스에 대한 참조이거나 될 null
수 있습니다.
17.2.3 배열 및 제네릭 컬렉션 인터페이스
1차원 배열 T[]
은 인터페이스 System.Collections.Generic.IList<T>
(IList<T>
짧은 경우)와 기본 인터페이스를 구현합니다. 따라서 해당 기본 인터페이스로 T[]
IList<T>
의 암시적 변환이 있습니다. 또한 다음으로 S
T
S[]
의 암시적 참조 변환이 구현 IList<T>
되고 해당 기본 인터페이스(§10.2.8)로 IList<T>
S[]
의 암시적 참조 변환이 있는 경우. 명시적 참조 변환 S
T
이 있는 경우 기본 인터페이스로 IList<T>
S[]
의 명시적 참조 변환이 있습니다(§10.3.5).
마찬가지로, 1차원 배열 T[]
은 인터페이스 System.Collections.Generic.IReadOnlyList<T>
(IReadOnlyList<T>
짧은 경우)와 기본 인터페이스도 구현합니다. 따라서 해당 기본 인터페이스로 T[]
IReadOnlyList<T>
의 암시적 변환이 있습니다. 또한 다음으로 S
T
S[]
의 암시적 참조 변환이 구현 IReadOnlyList<T>
되고 해당 기본 인터페이스(§10.2.8)로 IReadOnlyList<T>
S[]
의 암시적 참조 변환이 있는 경우. 명시적 참조 변환 S
T
이 있는 경우 기본 인터페이스로 IReadOnlyList<T>
S[]
의 명시적 참조 변환이 있습니다(§10.3.5).
예: 예:
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[]
에 예외가 throw됩니다. 그러나 캐스트는 (IList<string>)oa2
를 참조string[]
하기 때문에oa2
예외가 throw되지 않습니다.끝 예제
암시적 또는 명시적 참조 변환이 있을 때마다 기본 인터페이스 S[]
에서 S[]
IList<T>
IList<T>
(§10.3.5)로의 명시적 참조 변환도 있습니다.
배열 형식 S[]
이 구현되면 IList<T>
구현된 인터페이스의 일부 멤버가 예외를 throw할 수 있습니다. 인터페이스 구현의 정확한 동작은 이 사양의 범위를 벗어집니다.
17.3 배열 만들기
배열 인스턴스는 array_creation_expressions(§12.8.16.5) 또는 array_initializer(§17.7)를 포함하는 필드 또는 지역 변수 선언에 의해 생성됩니다. 매개 변수 배열(§15.6.2.4)과 관련된 인수 목록을 평가하는 과정의 일부로 배열 인스턴스를 암시적으로 만들 수도 있습니다.
배열 인스턴스가 만들어지면 각 차원의 순위와 길이가 설정되고 인스턴스의 전체 수명 동안 일정하게 유지됩니다. 즉, 기존 배열 인스턴스의 순위를 변경할 수 없으며 차원의 크기를 조정할 수도 없습니다.
배열 인스턴스는 항상 배열 형식입니다. 형식은 System.Array
인스턴스화할 수 없는 추상 형식입니다.
array_creation_expression만든 배열의 요소는 항상 기본값(§9.3)으로 초기화됩니다.
17.4 Array 요소 액세스
배열 요소는 배열 형식의 식이고 각각 Iₑ
은 형식long
uint
ulong
int
의 식인 양식 A[I₁, I₂, ..., Iₓ]
A
의 element_access 식(§12.8.11.2)을 사용하여 액세스하거나 이러한 형식 중 하나 이상으로 암시적으로 변환할 수 있습니다. 배열 요소 액세스의 결과는 변수, 즉 인덱스에 의해 선택된 배열 요소입니다.
문(§13.9.5)을 사용하여 foreach
배열의 요소를 열거할 수 있습니다.
17.5 배열 멤버
모든 배열 형식은 형식에 의해 선언된 멤버를 상속합니다 System.Array
.
17.6 배열 공변성
두 reference_typeA
B
및 암시적 참조 변환(§10.2.8) 또는 명시적 참조 변환(§10.3.5)A
B
이 있는 경우 배열 형식에서 배열 형식 A[R]
B[R]
으로 동일한 참조 변환이 존재합니다. 여기서 R
지정된 rank_specifier(두 배열 형식 모두 동일함). 이 관계를 배열 공변성이라고 합니다. 특히 배열 공변은 암시적 참조 변환이 있는 경우 배열 형식 A[R]
의 값이 실제로 배열 형식 B[R]
의 인스턴스에 대한 참조일 수 있음을 의미합니다 B
A
.
배열 공변성 때문에 참조 형식 배열의 요소에 대한 할당에는 배열 요소에 할당되는 값이 실제로 허용되는 형식(§12.21.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]
에는 실제 요소 형식array
과 호환되는 형식의 개체에 대한 참조 또는 참조인지 확인하는value
null
런타임 검사가 암시적으로 포함Fill
됩니다. 에서Main
처음 두Fill
호출은 성공하지만 세 번째 호출System.ArrayTypeMismatchException
은 첫 번째 할당을 실행할 때 throw됩니다array[i]
. boxedint
를 배열에 저장할 수 없기 때문에 예외가string
발생합니다.끝 예제
배열 공변은 특히 value_type배열로 확장되지 않습니다. 예를 들어 변환으로 처리object[]
할 수 있는 int[]
변환이 없습니다.
17.7 배열 이니셜라이저
배열 이니셜라이저는 필드 선언(§15.5), 지역 변수 선언(§13.6.2) 및 배열 생성 식(§12.8.16.5)에서 지정할 수 있습니다.
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};
1차원 배열의 경우 배열 이니셜라이저는 각각 배열의 요소 형식(§10.2)으로 암시적으로 변환되는 식 시퀀스로 구성되어야 합니다. 식은 인덱스 0의 요소부터 시작하여 배열 요소를 순서대로 초기화합니다. 배열 이니셜라이저의 식 수는 생성되는 배열 인스턴스의 길이를 결정합니다.
예: 위의 배열 이니셜라이저는 길이 5의 인스턴스를 만든
int[]
다음 다음 값을 사용하여 인스턴스를 초기화합니다.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이고 맨 오른쪽 차원의 길이가 2인 2차원 배열을 만듭니다.
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;
끝 예제
맨 오른쪽이 아닌 차원이 길이가 0인 경우 후속 차원의 길이도 0으로 간주됩니다.
예제:
int[,] c = {};
는 가장 왼쪽과 오른쪽 차원 모두에 대해 길이가 0인 2차원 배열을 만듭니다.
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