이 C # 사전 초기화는 어떻게 정확합니까?


64

나는 다음을 우연히 발견하고 왜 구문 오류가 발생하지 않았는지 궁금합니다.

var dict = new Dictionary<string, object>
{
    ["Id"] = Guid.NewGuid(),
    ["Tribes"] = new List<int> { 4, 5 },
    ["MyA"] = new Dictionary<string, object>
    {
        ["Name"] = "Solo",
        ["Points"] = 88
    }
    ["OtherAs"] = new List<Dictionary<string, object>>
    {
        new Dictionary<string, object>
        {
            ["Points"] = 1999
        }
    }
};

"MyA"와 "OtherAs"사이에 ","가 없습니다.

혼란이 일어나는 곳입니다.

  1. 코드가 컴파일됩니다.
  2. 마지막 사전 "dict"에는 "Id", "Tribes"및 "MyA"의 세 가지 요소 만 포함됩니다.
  3. "MyA"를 제외한 모든 값이 정확합니다.
  4. "MyA"는 "OtherAs"에 대해 선언 된 값을 취하지 만 원래 값은 무시됩니다.

왜 이것이 불법이 아닙니까? 의도적으로 설계된 것입니까?


1
@Steve 그것이 그가 요구하는 것입니다. 나는 sharplab에이 붙여 그것은 처음에 보이는 OtherAs무엇에 키로 추가됩니다 MyA 사전. (Name = Solo, Points = 88 plus OtherAs = List <Dictionary <string, object >>) 제외하고 는 할당하지 않습니다 . 대신 dicts 목록을 배치하고 MyA슬롯에 하나의 Points = 1999 항목 만 포함되어 있으므로 dicts 목록을 배치합니다 .
pinkfloydx33

1
첫 댓글에 붙여 넣기에 링크가 너무 깁니다. 실제로 이상하다. sharplab.io/...
pinkfloydx33

1
예, LinqPad로 테스트했으며 동일한 결과를 얻었습니다. 무슨 일이 일어나고 있는지 잘 모르겠습니다. 일부 C # 전문가가 여기에 약간의 빛을 비출 수 있는지 봅시다.
스티브

1
첫 번째 사전을 <string, string> and modify Points to "88" 로 변경하면 컴파일러 오류 "암시 적으로 'System.Collections.Generic.List <System.Collections.Generic.Dictionary <string, object >>'를 'string'으로 변환 할 수 없습니다"라는 오류가 발생합니다. 실제로 대답을 알아내는 데 도움이되었습니다!
pinkfloydx33

2
@OlegI 컴파일러 버그라고 생각하지 않습니다. 많은 좋은 설명이 이미 답변에 제공되어 있습니다. 그러나 시도 var test = new Dictionary<string, object> { ["Name"] = "Solo", ["Points"] = 88 }["OtherAs"] = new List<Dictionary<string, object>> { new Dictionary<string, object> { ["Points"] = 1999 } };하면 더 자세히 설명 할 것입니다.
MKR

답변:


54

누락 된 쉼표는 모든 차이를 만듭니다. ["OtherAs"]이 사전에 인덱서 가 적용됩니다.

new Dictionary<string, object>
{
    ["Name"] = "Solo",
    ["Points"] = 88
}

본질적으로 당신은 말하고 있습니다 :

new Dictionary<string, object>
{
    ["Name"] = "Solo",
    ["Points"] = 88
}["OtherAs"] = new List<Dictionary<string, object>>
{
    new Dictionary<string, object>
    {
        ["Points"] = 1999
    }
};

이것은 대입 식 ( x = y)입니다. 여기 x에 인덱스, "이름"과 "포인트"와 사전입니다 "OtherAs"y입니다 List<Dictionary<string, object>>. 대입 식은 대입 목록 인 대입되는 값 ( y) 으로 평가됩니다 .

이 전체 표현식의 결과는 "MyA"키에 할당되므로 "MyA"에 사전 목록이 있습니다.

사전 유형을 변경하여 현재 상황을 확인할 수 있습니다 x.

new Dictionary<int, object>
{
    [1] = "Solo",
    [2] = 88
}
// compiler error saying "can't convert string to int"
// so indeed this indexer is applied to the previous dictionary
["OtherAs"] = new List<Dictionary<string, object>>
{
    new Dictionary<string, object>
    {
        ["Points"] = 1999
    }
}

다음은 코드이지만 형식을 다시 지정하고 일부 괄호를 추가하여 컴파일러의 구문 분석 방법을 보여줍니다.

["MyA"] 
= 
(
    (
        new Dictionary<string, object>
        {
            ["Name"] = "Solo",
            ["Points"] = 88
        }["OtherAs"] 
    )
    = 
    (
        new List<Dictionary<string, object>>
        {
            new Dictionary<string, object>
            {
                ["Points"] = 1999
            }
        }
    )
)

1
그것은에서 사전의 값 유형을 변경 한 objectstring그것이 나에게 유사한 오류 메시지와 준 아하 답을 촉발 순간을. 당신이 저를 이길 것 같습니다-나는 전화에 답을 입력하는 것을 탓합니다 :-p
pinkfloydx33

19

여기서 일어나는 일은 사전을 만들고 색인을 생성하는 것입니다. 그런 다음 인덱서 / 할당 식의 결과가 반환되고 MyA사전 슬롯에 할당됩니다 .

이:

["MyA"] = new Dictionary<string, string> 
{
   ["Name"] = "Solo",
   ["Points"] = "88" 
}
["OtherAs"] = new List<Dictionary<string, object>>
{
   new Dictionary<string, object>
   {
       ["Points"] = 1999
   }
}

다음 의사 코드로 나눌 수 있습니다.

var temp = new Dictionary<string, object>
{ 
   ["Name"] = "Solo", 
   ["Points"] = 88 
};
// indexed contains result of assignment
var indexed = temp["OtherAs"] = new List<Dictionary<string, object>>
{
   new Dictionary<string, object>
   {
      ["Points"] = 1999
   }
};
// value is set to result of assignment from previous step
["MyA"] = indexed;
// temp is discarded

두 번째 사전의 인덱서에 할당 한 결과가 반환됩니다 (할당은 할당 된 값 / 오른쪽 값을 반환 함).이 사전은 "에더로 사라지는"임시 로컬입니다. 인덱서 (사전 목록)의 결과는 결국 기본 사전에 배치됩니다.

이것은 object사전 값의 유형으로 사용하기 때문에 더 쉽게 빠질 수있는 이상한 경우 입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.