【问题标题】:C# 6.0's new Dictionary Initializer - Clarification [duplicate]C# 6.0 的新字典初始化器 - 澄清 [重复]
【发布时间】:2015-03-20 11:57:36
【问题描述】:

我读过:

团队通常忙于实施其他变体 初始化器。例如,您现在可以初始化一个 Dictionary 对象

但是看着:

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

对比

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

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

问题:

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

【问题讨论】:

  • 没有任何好处。它只是看起来更像节点式的。
  • @TravisJ 我觉得这很奇怪(“没有好处......”),$xxx 很好,但想想他们只是从花括号变成了括号......?
  • 这只是一个变体。我想如果有的话,它的好处可能是它对不同编程背景的人来说读起来更好。但除此之外,它并没有真正改变字典的功能,或者让它拥有某种新的魔力:)
  • @TravisJ 有一个好处 - 您现在可以使用索引器“内联初始化”任何类型,即使它不适用于集合初始化器。

标签: c# dictionary c#-6.0 collection-initializer


【解决方案1】:

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

例如,你可以这样做:

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&lt;T&gt; 并具有 Add 方法的类型。这恰好适用于 Dictionary&lt;TKey,TValue&gt;,但这并不意味着它适用于任何基于索引的类型。

【讨论】:

  • Reed ,有点偏离主题,但仍然相关 - 我还看到(在视频中,现在)c#6 也在寻找 Add 方法,除了实例方法,我的意思是它可能是在扩展方法中。所以如果有人有一个名为 Insert 的方法,你将无法做到 new MyIenumerableType&lt;&gt; { {...,...},{...,...}} 因为它的类型没有 Add 方法。但 C#6 也会搜索 Add 作为扩展方法。 (如果您无法控制代码)
  • @RoyiNamir:我简要介绍了this answer 中的扩展添加方法。这一添加打开了大门,让使用收藏变得更加精彩。
  • @RoyiNamir 是的,但它仍然需要定义IEnumerable&lt;T&gt;,所以它的限制较少,但仍然有些限制。
  • 有趣...所以它基本上直接引用Dictionary 类上的公共TValue this[TKey key] 属性。就像任何构造函数都允许像User parkOwner = new User() { LastName = "Hammond", FirstName = "John" }; 这样的属性初始化器。它甚至不再与收藏真正相关。
【解决方案2】:

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

Collection Initializers:

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

所以这样定义的类可以使用以下语法:

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 或具有 add 方法,因此不能使用该语法。


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

能够在单个表达式中完全初始化对象通常很有用(在某些情况下,这是一项要求)。字典初始值设定项语法使执行此操作更容易,而无需使用集合初始值设定项。

【讨论】:

    【解决方案3】:

    这可能是一个值得商榷的功能,但新语法允许您多次设置相同的内容。

            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)
    

    【讨论】:

      【解决方案4】:

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

      对象和集合初始化器对于以声明方式初始化对象的字段和属性或为集合提供一组初始元素很有用。使用索引器初始化字典和其他对象不太优雅。我们正在向对象初始化器添加新语法,允许您通过新对象具有的任何索引器为键设置值

      【讨论】:

      • 有一个好处,您不会得到 ArgumentException “已添加具有相同密钥的项目。”如果您使用索引初始化语法。如果您克隆字典然后更改一些可能已经存在或不存在的值,这很有用。
      • @Finickyflame 已经可以使用 C#6 之前的语法(而不是调用 .Add())。
      • 新语法明确地是 not 语法糖。它有不同的行为。例如,重复的键条目将在运行时抛出原始的,但不会使用新语法。
      猜你喜欢
      • 2015-11-24
      • 2017-04-18
      • 2017-11-15
      • 2018-07-14
      • 2018-05-02
      • 2017-11-21
      • 2011-06-09
      • 2018-10-22
      • 2016-02-14
      相关资源
      最近更新 更多