C #에서 "인라인"배열을 사용할 수 없습니까?


92

어딘가에 이것을 가지고 있다고 상상해보십시오.

public static T AnyOne<T>(this T[] ra) where T:class
    {
    int k = ra.Length;
    int r = Random.Range(0,k);
    return ra[r];
    }

또는 이것 만

public static string OneOf(this string[] strings)
    {
    return "a";
    }

그럼 물론 할 수 있습니다 ...

string[] st = {"a","b","c"};
string letter = st.AnyOne();

... 대단합니다. 그러나. 이렇게 할 수없는 것처럼 보입니다.

string letter = {"a","b","c"}.AnyOne();

또는 실제로 아마도 이것은

string letter = ( {"a","b","c"} ).AnyOne();

또는 내가 시도한 다른 것.

사실 (1) 왜 그렇게 할 수 없습니까? 그리고 (2) 내가 뭔가를 놓치고 있는데, 방법이 있다면 어떻게 하시겠습니까?


5
중복 질문이 적절한 지 잘 모르겠습니다. OP는 배열 이니셜 라이저에 대해 묻지 않지만 컴파일러가 할당 될 때까지 개체를 배열로 인식하지 않는 이유는 무엇입니까?
Ron Beyer

4
나는 C # 용어에 익숙하지 않지만 이것이 더 일반적으로 인라인 보다는 리터럴 또는 배열 리터럴 이라고 생각합니다 .
chi

3
해당 구문 요소 는 사용되는 컨텍스트에 따라 배열 이니셜 라이저 또는 컬렉션 이니셜 라이저 입니다. 두 경우 모두 표현식으로 분류되지 않습니다 .
Eric Lippert

답변:


132

먼저를 사용하여 배열을 만들어야합니다 new[].

string letter = (new[] {"a","b","c"}).AnyOne();

@hvd가 언급했듯이 parantheses없이 이것을 할 수 있습니다 (..). 더 읽기 쉽다고 생각하기 때문에 parantheses를 추가했습니다.

string letter = new[] {"a","b","c"}.AnyOne();

그리고 new string[]다른 답변에서 언급했듯이 데이터 유형 을 지정할 수 있습니다 .


그렇게 할 수는 없습니다 {"a","b","c"}. 배열을 만드는 것이 아니라 배열을 채우는 방법으로 생각할 수 있기 때문입니다.

또 다른 이유는 컴파일러가 혼란스럽고, 예를 들어 a string[]{ .. }또는 List<string>{ .. }.

new[]컴파일러 만 사용하면 데이터 유형 ( ".."), 사이 {..}, 원하는 것을 알 수 있습니다 ( string). 필수 부분은 [], 즉 배열을 원한다는 것을 의미합니다.

.NET으로 빈 배열을 만들 수도 없습니다 new[].

string[] array = new []{ }; // Error: No best type found for implicity-typed array

13
이러한 괄호는 필요하지 않습니다. string letter = new[] {"a","b","c"}.AnyOne();괜찮습니다. 원하는 경우 괄호로 더 읽기 쉽다고 생각하면 타당하지만,이 경우에는 언어에 의해 강요되지 않은 의식적인 선택이라는 점을 언급 할 가치가 있다고 생각합니다.

new [] {1,2} 구문에 대해 알고 있지만 더 간단한 구문이 있습니까? [1, 2] 같은 거?
seguso

51

(1) 왜 그렇게 할 수 없습니까? {"a","b","c"}.AnyOne();

이 줄 :

string[] st = {"a","b","c"};

동등한 배열 생성 표현식 ( ILSpy 아래 ) 에 대한 약식 입니다.

string[] st = new string[]  {"a","b","c"};

이것은 string[] st = {"a","b","c"} 선언 할 때만 사용할 수 있으며 다른 곳에서 사용할 수 없으며 할 수도 없습니다.

string[] st;
st = {"a", "b", "c"}; //Error

C # 언어 사양의 배열 생성 표현에 대해서는 7.6.10.4 절에 설명되어 있습니다.

따라서 "{"a", "b", "c"}"선언에서 사용하지 않는 것은 아무것도 의미하지 않습니다. 따라서 확장 메서드가 배열에서 작동하므로 확장 메서드와 함께 사용할 수 없습니다.

(2) 내가 뭔가를 놓치고 있는데, 방법이 있다면 어떻게 하시겠습니까?

@adricadar의 답변 에서 이미 언급 했으므로 다음을 수행 할 수 있습니다.

(new[] {"a","b","c"}).AnyOne();

또는

(new string[] {"a","b","c"}).AnyOne();

48

나는 "왜 안 되는가"질문에 대해 반박합니다. 왜냐하면 먼저 대답이 거의 만족스럽지 못하기 때문입니다. "사양이 원하는 말을 말하지 않기 때문에 기능이 원하는 방식이 아닙니다"라는 대답을 이미 얻었습니다. , 내가 생각하기에 특별히 만족스러운 대답은 아니었다. 둘째, 디자인 팀은 세상이 당신이 원하는 방식 이 아닌 이유를 정당화 할 필요 가 없습니다 . 기능은 무료로 존재하지 않으며 언어로 설계되었습니다. 오히려 기능을 먼저 정당화 한 다음 설계해야합니다.

따라서 "왜 안 되는가"질문을 좀 더 명확하게 만들어 보겠습니다. 기존 기능은 "배열 이니셜 라이저는 (a) 초기화에서 등호의 오른쪽에 또는 (b) 배열 유형의 객체 구성의 오른쪽에 사용할 수 있습니다."입니다. 제안 된 기능은 "배열 이니셜 라이저도 표현식으로 사용할 수 있습니다."입니다. 질문은 "Eric이 제안 된 기능에 대해 어떤 비판을할까요?"입니다.

첫 번째 비판은 표현의 유형이 무엇인지 불분명하다는 것입니다. 변수 이니셜 라이저에는 변수 유형이 있고 객체 생성 표현식에는 객체 유형이 있습니다. 이 두 가지로부터 우리는 생성 된 배열의 유형을 추론 할 수 있습니다. 힌트없이 어떤 유형을 추론해야합니까?

C # 1.0에서는이 기능이 추가되었을 때 언어에서 총 0 개의 유형 추론이 수행되었습니다. C # 초창기의 디자인 원칙은 "놀랍지 않은"것이었고 컴파일러는 "너무 똑똑"하지 않았습니다. 개발자가 특정 유형의 표현식을 의도하는 경우 해당 유형은 표현식에서 어떤 식 으로든 분명해야합니다. 네가 얘기 할 때

new double[] { 1, 2, 3.4 }

어떤 유형이 의도되었는지는 매우 명확합니다. 비슷하게

new Animal[] { cat, dog, null }

제안 된 기능은이 원칙을 위반합니다. 표현식에는 유형이 있어야하지만 인수 유형이 무엇인지는 분명하지 않습니다.

M({cat, dog, null})

또한, 우리는 두 가지가 있다고 가정 과부하 M의 배열을 그 중 하나 Animal와 배열을 필요 하나 IPet. 어떤 과부하 M가 적용됩니까? 전환 중 하나가 다른 것보다 낫습니까? 요소 유형은 CatDog; 거기에 나타나지 않는 유형을 추론하는 것이 합리적입니까? 이것들은 모두 디자인 팀이 고려해야 할 질문이며, 분명한 답이없는 질문입니다. 제안 된 기능은 우리를 아주 짧은 시간에 깊은 물로 인도합니다.

이제 C # 3.0은 컴파일러가 개발자를 대신하여 형식을 유추하는 다양한 기능을 추가했기 때문에이 문제를 해결합니다. "놀람 없음"및 "간단한 규칙"에 대한 이전 원칙은 LINQ를 작동시키는 데 필요한 다른 디자인 원칙과 충돌했습니다. 제안한 기능이 C # 3.0에 추가 되었습니까?

그럴 수도 있습니다. 실제로 C # 3.0에 추가 된 기능은 다음과 같습니다.

new[] { x, y, z }

알고리즘을 사용하여 배열의 유형을 추론합니다. 유형이있는 요소에 대한 표현식을 가져 와서 이러한 유형 중 어떤 유형이 다른 모든 표현식을 변환 할 수있는 가장 일반적인 유형인지 결정하고 그러한 유형이 존재하는 경우 선택합니다. 그렇지 않으면 오류가 발생합니다.

이 기능은 new[]선택 사항 으로 만들기 위해 더 완화되었을 수 있습니다 . 이것은 완료되지 않았습니다.

이제 C # 3.0 시간대에서 제안 된 기능을 비판 해달라고 요청했다면 (1) C # 3.0 컴파일러가 이미 전체 릴리스의 일정을 늦출 위험에 처해 있었다고 지적했을 것입니다. 따라서 더 이상 추가하지 않겠습니다. 사용자에게 여섯 번의 키 입력 을 저장하는 완전히 불필요한 기능에 대한 설계, 구현 및 테스트 부담 과 (2) C # 3.0도 컬렉션 이니셜 라이저를 추가했습니다.

new List<int>() { 10, 20, 30 }

{10, 20, 30}자동으로 배열 이어야 합니까? 왜 안돼 List<int>? 아니면 다른 여러 유형 중 하나? 왜 배열에 대한 편향입니까? 기억 우리가 배열의 구문을 안치을 선택하면, 우리는 영원히 그것으로 붙어 있습니다 . 그것은 결코 수 아무것도 제안 기능뿐만 아니라 불필요한 그래서 그것은 또한 그럴듯 가능한 미래의 기능을 방지, 다른.

요약 : 제안 된 기능은 C # 1.0의 일부 디자인 원칙을 직접 위반했습니다. C # 3.0에 불필요한 부담 만 추가합니다. C # 3.0 이후의 모든 버전의 언어에서 제안 된 기능은 다른 많은 가치있는 기능보다 시간, 노력 및 비용을 소비하도록 권장하는 좋은 주장이 없습니다.

따라서 그러한 기능이 없습니다.


Heh, "세상은 당신이 원하는 방식이 아닙니다"라고 인쇄 된
티셔츠를 받아야

6
@JoeBlow : 우선, 천만에요. "왜 안 되는가"와 관련하여 귀하의 의견은 문제를 잘 보여줍니다. 어떤 사람들은 "왜"라는 질문을 할 때 논리적 정당성을 찾고 있습니다. 어떤 사람들은 실용적인 정당성을 찾고 있습니다. 그리고 분명히 규칙을 설명하는 사양 라인을 찾고 있습니다. 너무 모호해서 질문자의 마음 속에있는 질문을 대상으로하는 좋은 답변을 만드는 것은 매우 어렵습니다. "왜 안돼"라는 질문은 존재조차하지 않는 것에 대한 모호한 질문 이기 때문에 더 나쁩니다 .
Eric Lippert

3
@EricLippert 존재하는 것들에 대한 질문 보다 훨씬 더 나쁩니다 . 팀과 함께 소프트웨어를 작업하는 경우 전체 팀은 1 년 내내 기능에 대해 생각하고 그 결과를 균형있게 조정합니다. 결정이 내려집니다. 기능 요청 및 '이유'는 정당성을 요구합니다. 그러나 누군가가 단지 무언가를 원한다는 것을 의미 하지 않는 이유 는 기본적으로 팀 자체의 판단에 의문을 제기합니다. 더 나쁜 것은 질문 하지 않는지 묻는 사람이 일반적으로 주제에 대해 거의 알지 못한다는 것입니다. 따라서 질문이 아닌 이유를 다시 밀어 붙이는 것이 완전히 공정하다고 생각합니다. 잘 했어 IMO.
atlaste
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.