C# 6.0 的新字典初始化器 - 说明

C# 6.0's new Dictionary Initializer - Clarification

我读过:

The team have generally been busy implementing other variations on initializers. For example you can now initialize a Dictionary object

但是看着:

var Dic = new Dictionary<string,int>{ {"x",3}, {"y",7} };

对比

var Dic = new Dictionary<string,int>{ ["x"]=3, ["y"]=7 };

我看不出好处在哪里。它看起来一样。两者都不过是一个名称-值集合。
他们将成对的大括号换成成对的方括号和一些逗号

问题:

使用新语法的附加价值是什么?一个真实世界的例子将不胜感激。

第一种情况的代码使用集合初始化语法。为了能够使用集合初始化器语法,class 必须:

Collection Initializers:

  1. 实现IEnumerable接口。
  2. 定义可访问的 Add() 方法。 (从C#6/VS2015开始,可能是一种扩展方法)

所以像这样定义的 class 可以使用语法:

public class CollectionInitializable : IEnumerable
{
    public void Add(int value) { ... }
    public void Add(string key, int value) { ... }
    public IEnumerator GetEnumerator() { ... }
}

var obj = new CollectionInitializable
{
    1,
    { "two", 3 },
};

并非所有对象都是 IEnumerable 或具有添加方法,因此不能使用该语法。


另一方面,许多对象定义(可设置的)索引器。这是使用字典初始化程序的地方。拥有索引器可能有意义,但不一定是 IEnumerable。有了字典初始化器,你不需要IEnumerable,你不需要Add()方法,你只需要一个索引器。

能够在单个表达式中完全初始化一个对象通常很有用(在某些情况下,这是一项要求)。字典初始化器语法使它更容易做到这一点,而无需使用集合初始化器的严格要求。

字典的主要优点是一致性。使用字典,初始化与使用看起来不一样。

例如,您可以这样做:

var dict = new Dictionary<int,string>();
dict[3] = "foo";
dict[42] = "bar";

但是使用初始化语法,你必须使用大括号:

var dict = new Dictionary<int,string>
{
    {3, "foo"},
    {42, "bar"}
};

新的 C#6 索引初始化语法使初始化语法与索引用法更加一致:

var dict = new Dictionary<int,string>
{ 
    [3] = "foo",
    [42] = "bar"
};

然而,更大的优势是这种语法还提供了允许您初始化其他类型的好处。任何具有索引器的类型都将允许通过此语法进行初始化,其中旧的集合初始化器仅适用于实现 IEnumerable<T> 并具有 Add 方法的类型。这恰好适用于 Dictionary<TKey,TValue>,但这并不意味着它适用于任何基于索引的类型。

本身没有技术优势;它只是语法糖(就像许多新的 C# 6 功能一样)。而C# feature descriptions PDF,其实只提了一个文雅的问题:

Object and collection initializers are useful for declaratively initializing fields and properties of objects, or giving a collection an initial set of elements. Initializing dictionaries and other objects with indexers is less elegant. We are adding a new syntax to object initializers allowing you to set values to keys through any indexer that the new object has

这可能是一个有问题的功能,但新语法允许您多次设置相同的内容。

        private static Dictionary<string, string> test1
        = new Dictionary<string, string>() {
            ["a"] = "b",
            ["a"] = "c"
        };

是允许的:这里键 "a" 的值为 "c".

相反,使用

private static Dictionary<string, string> test2
    = new Dictionary<string, string>() {
        { "a","b" },
        { "a","c" },
    };

创建异常:

Unbehandelte Ausnahme: System.TypeInitializationException: Der Typeninitialisierer für "ConsoleApplication1.Program" hat eine Ausnahme verursacht. 
---> System.ArgumentException: Ein Element mit dem gleichen Schlüssel wurde bereits hinzugefügt.
   bei System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
   bei System.Collections.Generic.Dictionary``2.Insert(TKey key, TValue value, Boolean add)
   bei System.Collections.Generic.Dictionary``2.Add(TKey key, TValue value)
   bei ConsoleApplication1.Program..cctor() in Program.cs:Zeile 19.
   --- Ende der internen Ausnahmestapelüberwachung ---
   bei ConsoleApplication1.Program.Main(String[] args)