Як правильна ініціалізація словника 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. Заключний словник "диктант" містить лише три елементи: "Id", "Plemen" та "MyA".
  3. Значення для всіх, крім "MyA", є правильним,
  4. "MyA" приймає оголошене значення для "OtherAs", тоді як його початкове значення ігнорується.

Чому це не незаконно? Це за дизайном?


1
@Steve ось про що він питає. Я вставив це в sharplab і, схоже , спочатку OtherAsдодається в якості ключа в той , що будеMyA словник. (Name = Solo, Points = 88 плюс OtherAs = Список <Словник <рядок, об'єкт >>), за винятком того, що він ніколи не призначає . Натомість він розміщує список диктів, тепер містить лише єдиний запис пунктів = 1999 у MyAслот, який переосмислює те, що, на його думку, там належить.
pinkfloydx33

1
Посилання було занадто довгим, щоб вставити його в перший коментар. Це справді дивно. sharplab.io / ...
pinkfloydx33

1
Так, я перевірив це з LinqPad і отримав такий же результат. Не впевнений, що тут відбувається. Давайте подивимось, чи міг би якийсь гуру С # пролити трохи світла.
Стів

1
Якщо ви змінили перший словник на <string, string> and modify Points to "88" `, тоді ви отримаєте помилку компілятора" Неможливо неявно перетворити тип "System.Collections.Generic.List <System.Collections.Generic.Dictionary <string, object >> 'to' 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
Вона змінюється типу значення Словника від objectдо , stringякий дав мені подібне повідомлення про помилку і ага момент , який викликав відповідь. Здається, ви мене побили - я звинувачую введення відповіді на своєму телефоні :-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
   }
}

Можна розділити на наступний psuedo-код:

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якості словника значень.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.