C #이 두 개의 int 배열 구문에서 다르게 작동하는 이유
C #의 배열은 참조 형식에 대해 암시 적으로 공변합니다 .
object[] listString = new string[] { "string1", "string2" };
그러나 값이 아닌 형식에, 그래서 당신은 변경하는 경우 string
에 int
, 당신은 컴파일 얻을 것이다 오류 :
object[] listInt = new int[] {0, 1}; // compile error
이제 우려 int
되는 것은 아래의 두 가지 구문과 같이 배열을 명시 적으로 선언하지 않고 int
에서만 구별 할 new[]
때 컴파일러가 다르게 처리한다는 것입니다.
object[] list1 = { 0, 1 }; //compile successfully
object[] list2 = new[] {0, 1}; //compile error
당신은 얻을 것이다 object[] list1 = { 0, 1 };
성공적으로 컴파일하지만, object[] list2= new[] {0, 1};
오류를 컴파일.
C # 컴파일러가
object[] list1 = { 0, 1 };
같이
object[] list1 = new object[]{ 0, 1 };
그러나
object[] list2 = new[] { 0, 1 };
같이
object[] list2 = new int[]{ 0, 1 }; //error because of co-variant
이 경우 C # 컴파일러가 다른 방식으로 작동하는 이유는 무엇입니까?
컴파일하는 버전은 배열 이니셜 라이저 를 사용하여 list1
. C # 언어 사양, §1.110 ( "배열 이니셜 라이저")은 다음과 같이 설명합니다.
배열 이니셜 라이저는 "{"및 "}"토큰으로 묶이고 ","토큰으로 구분 된 일련의 변수 이니셜 라이저로 구성됩니다. 각 변수 이니셜 라이저는 표현식이거나 다차원 배열의 경우 중첩 배열 이니셜 라이저입니다.
배열 이니셜 라이저가 사용되는 컨텍스트는 초기화되는 배열의 유형을 결정합니다. 배열 생성 식에서 배열 유형은 이니셜 라이저 바로 앞에 있거나 배열 이니셜 라이저의 식에서 유추됩니다. 필드 또는 변수 선언에서 배열 유형은 선언되는 필드 또는 변수의 유형입니다.
배열 이니셜 라이저가 다음과 같이 필드 또는 변수 선언에 사용되는 경우 :
int[] a = {0, 2, 4, 6, 8};
동등한 배열 생성 표현식의 축약 형입니다.
int[] a = new int[] {0, 2, 4, 6, 8};
따라서 이것이 컴파일되어야한다는 것이 분명합니다.
두 번째 버전은 명시 적 배열 생성 표현식 을 사용합니다. 여기서 컴파일러에게 생성 할 배열 유형을 구체적으로 지시합니다. §1.51.10.4 ( "배열 생성 표현식")는 다음과 같이 설명합니다.
세 번째 형식의 배열 생성 식을 암시 적으로 형식화 된 배열 생성식이라고 합니다. 배열의 요소 유형이 명시 적으로 지정되지 않고 배열 이니셜 라이저의 식 집합 중 가장 일반적인 유형 (§1.50.2.14)으로 결정된다는 점을 제외하면 두 번째 형식과 유사합니다.
따라서 두 번째 버전은 다음과 같습니다.
object[] list2 = new int[] { 0, 1 };
문제는 지금 효과적으로된다 그래서 "왜 나는를 할당 할 수 없습니다 int[]
에 object[]
당신이 질문의 끝에서 언급하는 것처럼." 그리고 답은 또한 간단합니다. §1.109 ( "배열 공분산")에 나와 있습니다.
배열 공분산은 특히 값 유형의 배열로 확장되지 않습니다. 예를 들어, 변환이 허용하는 경우 해당 존재하지
int[]
로 취급object[]
.
선언
object[] listInt = new int[] {0, 1};
값 유형에 대해 공변 배열 변환이 허용되지 않고 값 유형이므로이 (가) 유효하지 않습니다 int
. 또는 선언
object[] listInt = new string[] {"0", "1"};
참조 유형에 대해 공변 배열 변환이 허용되기 때문에 유효합니다. 이는 할당 x = (object)myString
이 단순 할당 만 포함 y = (object)myInt
하고 권투 작업이 필요하기 때문입니다.
이제 두 선언의 차이점을 살펴 보겠습니다. 선언 object[] list2 = new[] { 0, 1 }
에서 유형 추론이 작동하는 방식으로 인해 먼저 오른쪽 표현식을 살펴보고 다음과 같이 new[] { 0, 1 }
처리해야한다고 결론을 내립니다 new int[] { 0, 1 }
. 그런 다음이 int 배열을 객체 배열에 할당하려고 시도하여 값 유형의 공변 변환 문제로 인해 오류가 발생합니다. 그러나 선언 object[] list1 = { 0, 1 }
은 컬렉션 이니셜 라이저를 사용하며, 이러한 상황에서 컬렉션 유형은 유형이 정의 된 위치이므로 각 요소는 대신 컬렉션에서 예상하는 유형으로 캐스팅됩니다.
당신이 사용하는 경우 {
와 }
, 당신이 컬렉션 이니셜 라이저를 사용 (참조 : http://msdn.microsoft.com/en-us/library/vstudio/bb384062.aspx을 ). 이러한 대괄호 사이의 값은 어딘가에 넣어야합니다. 따라서 컬렉션을 만들어야합니다. 컴파일러는 컨텍스트를 분석하여 어떤 종류의 컬렉션을 찾습니다.
첫 번째 경우 : object[] list1 = { 0, 1 };
컬렉션이 생성되어야한다는 것이 분명합니다. 하지만 어떤 종류 여야합니까? new
어딘가에 작업 이 없습니다 . 힌트는 하나뿐입니다. list1
is of type object[]
입니다. 따라서 컴파일러는 해당 컬렉션을 생성하고 값으로 채 웁니다.
두 번째 예 object[] list1 = new[] { 0, 1 };
에는 또 다른 힌트가 new[]
있습니다.. 그리고이 힌트는 명시 적으로 말합니다 : 배열이있을 것입니다. 해당 배열에는 유형이 없으므로 값을 분석하여 배열 유형을 찾으려고합니다. 이것들은 모두 int
의 것이므로의 배열을 만들고 int
채 웁니다. 다른 힌트 object[]
는 생성에 대한 힌트가 할당되어야하는 힌트보다 훨씬 더 중요하기 때문에 완전히 무시됩니다. 이제 컴파일러는이 배열을 list1 및 BOOM에 할당하려고합니다. 맞지 않습니다!
이 명령문 object[] list1 = { 0, 1 };
은 컴파일러가 숫자 형식 배열을 참조 형식 배열로 변환하려고 시도하고 있음을 알 수있을만큼 똑똑하기 때문에 Int32 요소를 참조 형식으로 상자에 넣습니다.
기본 유형을 명시 적으로 상자에 넣을 수도 있습니다.
object[] list2 = Array.ConvertAll<int, Object>(new[] { 0, 1 }, input => (Object)input);
배열 형식으로 'int []'또는 'Int32 []'를 지정한 경우 컴파일러는 암시 적으로 boxing을 수행하지 않지만 C #에 추가 할 수있는 것처럼 보입니다.
배열 이니셜 라이저는 컴파일러의 편의입니다. "나는 객체의 배열을 선언하고 값을 할당하고 있습니다"라고 말하면 컴파일러가 당신 { 0, 1 }
이 객체 배열 이라고 가정하고 그것을 그렇게 해석하는 것이 합리적입니다 . 구문이 할당으로 보이지만 그렇지 않습니다. 이니셜 라이저를 사용하고 있습니다. 이 구문의 약어는 다음과 같습니다.object[] list1 = new object[] { 0, 1 }
When you say new[] { 0, 1 }
, this is an expression that creates an array and initialises it. This expression is evaluated independently of what you're assigning it to - and because the compiler detects the implicit integer typing, it creates an int[]
. The longhand version of that expression is object[] list2 = new int[] { 0, 1 }
If you compare the longhand versions of these two statements, it's clear to see where they differ.
object[] listInt = new int[] {0, 1};
is shorthand for
object[] listInt;
listInt = new int[] {0, 1};
which doesn't work because int[]
is not covariant with object[]
.
And when you say new[]
, it is equivalent to new int[]
, hence the same applies.
'developer tip' 카테고리의 다른 글
Cypress : 요소가 존재하지 않는지 테스트 (0) | 2020.11.05 |
---|---|
숫자 유형을 객체 키로 사용하는 방법이 있습니까? (0) | 2020.11.05 |
대체 사전을 사용하여 문자열을 대체하는 가장 쉬운 방법은 무엇입니까? (0) | 2020.11.04 |
Python 스크립트 중간에있는 모든 변수를 지우려면 어떻게해야합니까? (0) | 2020.11.04 |
스트림에서 가져온 이미지 형식을 어떻게 알 수 있습니까? (0) | 2020.11.04 |