[c#] C #에서 “인라인”배열을 사용할 수 없습니까?

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

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) 내가 뭔가를 놓치고 있는데, 방법이 있다면 어떻게 하시겠습니까?



답변

먼저를 사용하여 배열을 만들어야합니다 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


답변

(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();


답변

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

따라서 “왜 안 되는가”질문을 좀 더 명확하게 만들어 보겠습니다. 기존 기능은 “배열 이니셜 라이저는 (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 이후의 모든 버전의 언어에서 제안 된 기능은 다른 많은 가치있는 기능보다 시간, 노력 및 비용을 소비하도록 권장하는 좋은 주장이 없습니다.

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


답변