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

在字典初始化器中使用方括号和大括号有区别吗?

c#
  •  3
  • laptou  · 技术社区  · 6 年前

    在字典初始值设定项中,有两种方法可以创建包含内容的字典:

    new Dictionary<string, GradientSpace>
    {
        ["userSpaceOnUse"] = GradientSpace.Absolute,
        ["objectBoundingBox"] = GradientSpace.Relative
    })
    

    new Dictionary<string, GradientSpace>
    {
        {"userSpaceOnUse", GradientSpace.Absolute},
        {"objectBoundingBox", GradientSpace.Relative}
    });
    

    这两种语法到底有什么区别,还是只是偏好的问题?

    1 回复  |  直到 6 年前
        1
  •  7
  •   marc_s Anurag    5 年前

    当源代码如下,目标框架为.NET 4.7.1时:

    var x = new Dictionary<string, int>
    {
        ["userSpaceOnUse"] = 1,
        ["objectBoundingBox"] = 3
    };
    
    var y = new Dictionary<string, int> {
        {"userSpaceOnUse", 1},
        {"objectBoundingBox", 3}
    };
    

    这将产生以下中间语言(使用JetBrains dotPeek):

    // [18 13 - 22 15]
    IL_0001: newobj       instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::.ctor()
    IL_0006: dup          
    IL_0007: ldstr        "userSpaceOnUse"
    IL_000c: ldc.i4.1     
    IL_000d: callvirt     instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::set_Item(!0/*string*/, !1/*int32*/)
    IL_0012: nop          
    IL_0013: dup          
    IL_0014: ldstr        "objectBoundingBox"
    IL_0019: ldc.i4.3     
    IL_001a: callvirt     instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::set_Item(!0/*string*/, !1/*int32*/)
    IL_001f: nop          
    IL_0020: stloc.0      // x
    
    // [25 13 - 28 15]
    IL_0021: newobj       instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::.ctor()
    IL_0026: dup          
    IL_0027: ldstr        "userSpaceOnUse"
    IL_002c: ldc.i4.1     
    IL_002d: callvirt     instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::Add(!0/*string*/, !1/*int32*/)
    IL_0032: nop          
    IL_0033: dup          
    IL_0034: ldstr        "objectBoundingBox"
    IL_0039: ldc.i4.3     
    IL_003a: callvirt     instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::Add(!0/*string*/, !1/*int32*/)
    IL_003f: nop          
    IL_0040: stloc.1      // y
    

    第一种方法导致设置索引器/属性,而第二种方法使用Add()方法,这意味着它们的转换方式不同。

    的.NET核心源 Dictionary 在这种情况下,类也很有趣: https://github.com/Microsoft/referencesource/blob/master/mscorlib/system/collections/generic/dictionary.cs

        2
  •  2
  •   Jeppe Stig Nielsen    5 年前

    [ … ] = … 必须使用 set

    tmpDict["userSpaceOnUse"] = GradientSpace.Absolute;
    tmpDict["objectBoundingBox"] = GradientSpace.Relative;
    

    而另一种语法则需要使用名称为 Add ,所以:

    tmpDict.Add("userSpaceOnUse", GradientSpace.Absolute);
    tmpDict.Add("objectBoundingBox, GradientSpace.Relative);
    

    对于特定类型 System.Collections.Generic.Dictionary<,> 方法)。因此,如果您(大概)意外地包含同一个键两次,如:

    new Dictionary<string, GradientSpace>
    {
      ["userSpaceOnUse"] = GradientSpace.Absolute,
      ["objectBoundingBox"] = GradientSpace.Relative,
      ["userSpaceOnUse"] = GradientSpace.Relative,
    }
    

    分别是:

    new Dictionary<string, GradientSpace>
    {
      { "userSpaceOnUse", GradientSpace.Absolute },
      { "objectBoundingBox", GradientSpace.Relative },
      { "userSpaceOnUse", GradientSpace.Relative },
    }
    

    你会感觉到不同!在第一种情况下,最后一次使用钥匙 "userSpaceOnUse" 只会覆盖第一个值(第一行 DuplicateKeyException 当你跑的时候。