代码之家  ›  专栏  ›  技术社区  ›  Dantte

这个c#字典初始化是如何正确的?

  •  5
  • Dantte  · 技术社区  · 5 年前

    我偶然发现了以下内容,我想知道为什么它没有引起语法错误。

    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 回复  |  直到 5 年前
        1
  •  55
  •   Sweeper    5 年前

    缺少的逗号使一切变得不同。它会导致索引器 ["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
                }
            }
        )
    )
    
        2
  •  20
  •   pinkfloydx33    5 年前

    这里发生的事情是,您正在创建一个字典,然后对其进行索引。然后返回索引器/赋值表达式的结果,这就是分配到 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 作为字典值的类型。