14

나는 항상 두 가지 방법으로 잘 작동한다고 생각했다. 그런 다음이 테스트를했고, 그것이 재 할당을 허용하지 않는다 실현 :재 할당시 컬렉션 초기화 프로그램이 허용되지 않는 이유는 무엇입니까?

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

잘 작동하지만 :

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

이에 대한 모든 기술적 인 이유? 나는이 행동이 내가 직관적으로 기대했던 것이기 때문에 내가 여기서 그것에 대해 물을 것이라고 생각했다.

+4

도움이 될 것입니다. http://stackoverflow.com/questions/7351453/why-cant-i-use-the-array-initializer-with-an-implicitly-typed-variable (엄격히 중복되지는 않음) –

답변

20

우선은,의이 용어가 올바른하자 쉽게의 xD 작동합니다. 그건 컬렉션 이니셜 라이저가 아닙니다. 그것은 배열 초기화 프로그램입니다. 콜렉션 이니셜 라이저는 항상 콜렉션 유형의 생성자를 따릅니다. 배열 이니셜 라이저는 로컬 또는 필드 선언 초기화 프로그램이나 배열 작성 표현식에서만 유효합니다.

당신은 이것이 이상한 규칙이라는 것에 완전히 틀림 없습니다. 그 괴괴 망측을 정확하게 묘사합시다 :

int 배열을 취하는 메서드 M이 있다고합시다. 이러한 모든 법률은 다음과 같습니다

int[] x = new[] { 10, 20, 30 }; 
int[] y = new int[] { 10, 20, 30 }; 
int[] z = new int[3] { 10, 20, 30 }; 
M(new[] { 10, 20, 30 }); 
M(new int[] { 10, 20, 30 }); 
M(new int[3] { 10, 20, 30 }); 

그러나

int[] q = {10, 20, 30}; // legal! 
M({ 10, 20, 30 }); // illegal! 

그것은 중 하나 "고독한"배열 초기화 해야지처럼 보인다는 어디서나 하나가 없거나 곳 "장식"고 법적으로. 이상하게도 표현식이 합법적이지 않은 이니셜 라이저에서만 유효한 의사 표현식이 있습니다.

나는이 선택을 비판하고 옹호하기 전에 무엇보다도이 불일치가 역사적인 사고라고 말하고 싶습니다. 그럴만한 이유가 없습니다. 우리가 코드를 위반하지 않고 제거 할 수 있다면, 우리는 그렇게 할 것입니다. 그러나 우리는 할 수 없습니다. 우리는 C#을 처음부터 다시 디자인 했었지 만, "new"가없는 "외로운"배열 초기화 프로그램은 유효한 구문이 아닐 가능성이 높습니다.

그래서 먼저 배열 초기화 기가 표현식으로 허용되어서는 안되며 로컬 변수 초기화기에 허용되어야하는 몇 가지 이유를 알려줍니다. 그렇다면 나는 그 반대의 이유를 몇 가지 제시 할 것이다. 왜 배열 이니셜 라이저 식으로 허용되어서는 안

이유 :

배열 이니셜 라이저 { 항상 코드의 새로운 블록의 도입을 의미하는 좋은 속성을 위반. 입력 중 파싱하는 IDE의 오류 복구 구문 분석기는 명령문이 불완전한시기를 알려주는 편리한 방법으로 중괄호를 사용하는 것을 좋아합니다. 당신이 볼 경우 :

if (x == M(
{ 
    Q(

을 코드 편집기 당신이 { 전에 )) 누락 추측하는 그 다음은 아주 간단합니다. 편집자는 Q(이 명령문의 시작이고 그 끝이 누락되었다고 가정합니다.

그러나 배열 이니셜 라이저 법적 표현하면 다음이없는 것을 그Q 다음 )})){}입니다 수 있습니다.

둘째, 배열 초기화 프로그램은 표현식으로 모든 힙 할당에 어딘가에 "새로운"것이 있다는 좋은 원칙을 위반합니다. 배열 이니셜 라이저는 필드와 지역의 초기화에 허용해야하는 이유

이유 :

그 배열 이니셜 라이저는 배열에, 1.0 버전의 언어 전에 암시 적으로 형식화 된 지역 주민, 익명 형식 또는 형식 유추를 추가 한 기억하십시오. 위로 하루에 우리가 가지고 있지 않은 기분 "새 [] {10, 20, 30} '구문, 당신이 말을해야 할 것 배열 이니셜 라이저가없는 있도록 : 매우 중복 보인다

int[] x = new int[] { 10, 20, 30 }; 

을! 나는 그들이 왜 그 "새로운 int []"을 꺼내고 싶어하는지 볼 수 있습니다.

당신이 구문 모호하지

int[] x = { 10, 20, 30 }; 

을 말할 때; 파서는 이것이 배열 초기화 자이며 코드 블록의 시작이 아니라는 것을 안다. (위에서 언급 한 경우와는 다르다.) 또한 타입 애매하다. 이니셜 라이저는 컨텍스트의 int 배열입니다.

이 인수는 C# 1.0에서는 배열 초기화자가 로컬 및 필드 초기화 프로그램에서 허용되지만 표현식 컨텍스트에서는 허용되지 않는 이유를 정당화합니다.

하지만 그건 우리가 현재 세계에있는 것이 아닙니다. 우리는 이것을 처음부터 디자인 했었을 것입니다. 아마 "new"가없는 배열 이니셜 라이저가 없을 것입니다. 요즘 물론 더 나은 해결책은 다음과 같습니다.

var x = new[] { 10, 20, 30 }; 

해당 표현식은 모든 문맥에서 유효합니다. 명시 적으로 입력하면 =의 "선언"쪽 또는 "이니셜 라이저"쪽에 명시 적으로 입력하거나 컴파일러에서 양쪽 또는 두 가지 유형을 추측하도록 할 수 있습니다.

그렇다면 배열 초기화 프로그램은 로컬 및 필드 선언에서만 사용할 수 있지만 표현식 컨텍스트에서는 사용할 수 없다는 것은 맞습니다. 10 년 전 좋은 이유가 있었지만 형식 유추가있는 현대 세계에서는 더 이상 그럴 이유가 없습니다. 이 시점에서 역사적인 사고 일뿐입니다.

+4

와우. 모든 C# 질문에 답변을 게시하면 StackOverflow가 1000 배 더 멋지게됩니다. –

+0

@JimSchubert : 나는 그 감정을 매우 고맙게 여긴다. 그러나 나는 그것이 더 나쁠 것이라고 확신한다. 나는 사이트에서 C# 질문의 99 %에 대한 답을 모른다! 나는 언어의 역사, 디자인 및 구현에 대한 전문가이다. 지난 6 년 간이를 집중적으로 살펴보면 실용적인 C# 프로그래밍의 거대한 영역이 있다는 것을 의미합니다. –

+0

어쨌든 대답을 읽는 것을 좋아합니다! – Matthias

1

이 될 최대량 : VB에서

int [] a;// ={1,2,3,4}; 
    a = new [] {1, 2, 3, 4}; 

는 선언과 같은 방식으로,

Dim a() As Integer '={1,2,3,4} 
a = {1, 2, 3, 4} 
+1

그는 왜이 제한이 있는지 묻습니다. –

+0

감사합니다. 전에'new []'를 추가하여 작동하게하십시오. 하지만 왜이 제한이 그것 없이도 작동 할 수있을 때 (그냥 처음에 할당 할 때) –

+0

글쎄, VB에서 할 수 있기 때문에 언어에 대한 것이라고 생각합니다. 우리는 MSIL 코드에서 diference . – Piyey