这个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的键添加的。(Name = Solo,Points = 88 plus OtherAs = List <Dictionary <string,object >>),但是它永远不会分配它。取而代之的是,它放置字典列表,现在仅在插槽中包含单个Points = 1999条目,从而覆盖了该位置所认为的内容。MyAMyA
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

Answers:


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字典值的类型,因此更容易陷入这种情况。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.