Hi, folks! Today we are gonna talk about new indexer initialization syntax introduced in C# 6.0. As we know, we already have good way to initialize dictionary:
var dic = new Dictionary<string, int>
{
{"Apple", 2},
{"Pear", 10}
};
but in C# 6.0 we have a better way to do the same:
var dic2 = new Dictionary<string, int>
{
["Apple"] = 2,
["Pear"] = 10
};
As for me, it is a bit nicer because we already have curly brackets in the beginning and ending of the initialization block in the "old" syntax, so it's a bit messy with all those '{' and '}'. But it's more about a taste and readability and not about functionality or productivity.
It is not only about dictionaries, you can use indexer initializer with any type that has indexer. Let's check following type:
public class Test
{
private int[] items = new int[100];
public string Property { get; set; }
public int this[int index]
{
set { items[index] = value; }
get { return items[index]; }
}
}
Now, you can use indexer initilaizer to initialize this class:
var test = new Test
{
[1] = 1,
[2] = 2,
Property = "123"
};
As you can see you can mix proprties and indexers in the initializetion block.
Here are a bit more examples:
var dic = new Dictionary<int, string>
{
[1] = "test",
[2] = "test2"
};
var list = new List<int>
{
[0] = 1,
[1] = 2
};
var dic3 = new Dictionary<CustomClass, string>
{
[new CustomClass()] = "test",
[new CustomClass()] = "test2"
};
var dic4 = new Dictionary<CustomClass, string>
{
[FactoryMethod()] = "test",
[CustomClass.Build()] = "test2"
};
Internal Implementation
Yes, it's just a syntactic sugar, nothing more. Even "old-school" initialization is just a syntactic sugar. Let's see following example:
var dic = new Dictionary<int, string>
{
[1] = "test",
[2] = "test2"
};
It will compile to the following code:
var dic = new Dictionary<int, string>();
dic.Add(1, "test");
dic.Add(1, "test2");
To check that, just decompile first example with ildasm.exe:
IL_0000: newobj instance void class [mscorlib]System.Collections.Generic.Dictionary`2<int32,string>::.ctor()
IL_0005: dup
IL_0006: ldc.i4.1
IL_0007: ldstr "test"
IL_000c: callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<int32,string>::Add(!0, !1)
IL_0011: dup
IL_0012: ldc.i4.2
IL_0013: ldstr "test2"
IL_0018: callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<int32,string>::Add(!0, !1)
Now let's see example with new initialization syntax:
var dic = new Dictionary<int, string>
{
[1] = "test",
[2] = "test2"
};
And the result is slightly different:
IL_0000: newobj instance void class [mscorlib]System.Collections.Generic.Dictionary`2<int32,string>::.ctor()
IL_0005: dup
IL_0006: ldc.i4.1
IL_0007: ldstr "test"
IL_000c: callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<int32,string>::set_Item(!0, !1)
IL_0011: dup
IL_0012: ldc.i4.2
IL_0013: ldstr "test2"
IL_0018: callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<int32,string>::set_Item(!0, !1)
C# equivalent:
var dic = new Dictionary<int, string>();
dic[1] = "test";
dic[2] = "test2";
As you can see, instead of calling Add method, indexer (internally implemented as an Item property) was used to set values.
In this case, there is no difference between this two implementations, because internally indexer and Add method will call private Insert methods to add the value into the dictionary.