C# 6.0's new Dictionary Initializer - Clarification [duplicate]
Asked Answered
E

4

21

I've read that :

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

But looking at :

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

vs.

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

I don't see where the benefit is. It looks the same. Both are nothing more than a name-value collection.
They swapped pairs of curly braces for pairs of square brackets and some commas

Question:

What is the added value for using the new syntax ? A real world example would be much appreciated.

Eldwen answered 21/1, 2015 at 20:21 Comment(4)
There is no benefit. It just looks more node-esque.Pickerel
@TravisJ I find this very weird ( "no benefit...") , well the $xxx is nice , but to think that they just changed from curly braces to brackets...?Eldwen
It is just a variation. I suppose the benefit if any is perhaps it reads better to people of different programming backgrounds. But other than that, it doesn't really change the functionality of a dictionary, or allow it to have some sort of new magical powers :)Pickerel
@TravisJ There is a benefit - you can now "inline initialize" any type with an indexer, even if it doesn't work with collection initializers.Calix
C
31

The main advantage here with a dictionary is consistency. With a dictionary, initialization did not look the same as usage.

For example, you could do:

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

But using initialization syntax, you had to use braces:

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

The new C# 6 index initialization syntax makes initialization syntax more consistent with index usage:

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

However, a bigger advantage is that this syntax also provides the benefit of allowing you to initialize other types. Any type with an indexer will allow initialization via this syntax, where the old collection initializers only works with types that implement IEnumerable<T> and have an Add method. That happened to work with a Dictionary<TKey,TValue>, but that doesn't mean that it worked with any index based type.

Calix answered 21/1, 2015 at 20:37 Comment(4)
Reed , abit offtopic , but still related - I've also seen ( in a video , right now) that c#6 also looks for Add method , beyond the instance method , I mean it could be in an extension method. so if someone has a method named Insert , you won't be able to do new MyIenumerableType<> { {...,...},{...,...}} becuase it the type doesn't has the Add method. but C#6 will search the Add also as an extension method. ( if you don't have control over the code)Eldwen
@RoyiNamir: I briefly go over the extension add methods in this answer. This addition opens up the door to make working with collections that much more awesome.Heartrending
@RoyiNamir Yes, but it still requires IEnumerable<T> to be defined, so it's less limited, but still somewhat limited.Calix
Interesting... so it's basically directly referencing the public TValue this[TKey key] property on the Dictionary class. Just like any constructor allows property initialisers like User parkOwner = new User() { LastName = "Hammond", FirstName = "John" };. It's not even really related to collections anymore.Hydr
H
9

The code in the first case uses the collection initializer syntax. To be able to use the collection initializer syntax, a class must:

Collection Initializers:

  1. Implement the IEnumerable interface.
  2. Define an accessible Add() method. (as of C#6/VS2015, it may be an extension method)

So a class defined like so may use the syntax:

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 },
};

Not all objects are IEnumerable or has an add method and therefore cannot use that syntax.


On the other hand, many objects define (settable) indexers. This is where the dicionary initializer is used. It might make sense to have indexers but not necessarily be IEnumerable. With the dictionary initializer, you don't need to be IEnumerable, you don't need an Add() method, you only need an indexer.

Being able fully initialize an object in a single expression is generally useful (and in some contexts, a requirement). The dictionary initializer syntax makes it easier to do that without the steep requirements of using collection initializers.

Heartrending answered 21/1, 2015 at 20:37 Comment(0)
C
9

It may be a questionable feature, but the new syntax allows you to set the same multiple times.

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

is allowed: here the key "a" has the value "c".

In contrast, using

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

creates an exception:

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)
Crust answered 28/2, 2016 at 18:54 Comment(0)
B
2

There's no technical benefit per se; it's just syntactic sugar (like many of the new C# 6 features). The C# feature descriptions PDF, in fact, mentions only a matter of elegance:

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

Behka answered 24/1, 2015 at 9:53 Comment(3)
There is a benefit, you won't get the ArgumentException "An item with the same key has already been added." if you are using the index initialization syntax. Which is useful if you clone your dictionary then change some values that may or not be already in.Rondeau
@Rondeau that was already possible with the pre-C#6 syntax (as opposed to calling .Add()).Behka
The new syntax is explicitly not syntactic sugar. It has different behaviors. For example, duplicate key entries will throw at runtime for the original, but not with the new syntax.Aureole

© 2022 - 2024 — McMap. All rights reserved.