Как это C# словарь инициализации правильно? - PullRequest
64 голосов
/ 02 февраля 2020

Я наткнулся на следующее, и мне интересно, почему оно не вызывает синтаксическую ошибку.

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 ", а его исходное значение игнорируется.

Почему это не незаконно? Это по замыслу?

Ответы [ 2 ]

54 голосов
/ 02 февраля 2020

Отсутствующая запятая имеет значение. Это заставляет индексатор ["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
            }
        }
    )
)
19 голосов
/ 02 февраля 2020

Здесь происходит то, что вы создаете словарь, а затем индексируете его. Затем возвращается результат выражения индексатора / присваивания, и это то, что присваивается в слоте словаря MyA.

Это:

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

Можно разделить на следующие psuedo-code:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...