What benefits does dictionary initializers add over collection initializers? - c#

In a recent past there has been a lot of talk about whats new in C# 6.0
One of the most talked about feature is using Dictionary initializers in C# 6.0
But wait we have been using collection initializers to initialize the collections and can very well initialize a Dictionary also in .NET 4.0 and .NET 4.5 (Don't know about old version) like
Dictionary<int, string> myDict = new Dictionary<int, string>() {
{ 1,"Pankaj"},
{ 2,"Pankaj"},
{ 3,"Pankaj"}
};
So what is there new in C# 6.0, What Dictionary Initializer they are talking about in C# 6.0

While you could initialize a dictionary with collection initializers, it's quite cumbersome. Especially for something that's supposed to be syntactic sugar.
Dictionary initializers are much cleaner:
var myDict = new Dictionary<int, string>
{
[1] = "Pankaj",
[2] = "Pankaj",
[3] = "Pankaj"
};
More importantly these initializers aren't just for dictionaries, they can be used for any object supporting an indexer, for example List<T>:
var array = new[] { 1, 2, 3 };
var list = new List<int>(array) { [1] = 5 };
foreach (var item in list)
{
Console.WriteLine(item);
}
Output:
1
5
3

Just to stress the most important difference, dictionary initializer calls the indexer, and hence it performs an update when duplicate keys are encountered, whereas collection initializer calls the Add method which will throw.
To briefly summarize the differences in general:
Collection initializer calls Add method (for IEnumerables) where as dictionary initializer calls indexer. This has the Add vs Update semantic differences for dictionaries.
Dictionary initializer is technically an object initializer, hence can be mixed with initializing other properties. For e.g.:
new Dictionary<int, string>
{
[1] = "Pankaj",
[2] = "Pankaj",
[3] = "Pankaj",
Capacity = 100,
};
but not
new Dictionary<int, string>()
{
{ 1,"Pankaj" },
{ 2,"Pankaj" },
{ 3,"Pankaj" },
Capacity = 100, // wont compile
};
Being just an object initializer, indexed initializer can be used for any class with an indexer, whereas collection initializer can be used only for IEnumerables, which should be obvious anyway.
Collection initializer can be enhanced with custom Add extension methods, whereas ditionary initializer can't be (no extension indexer in C# yet).
Dictionary initializer maybe subjectively slightly more readable when it comes to initializing a dictionary :)
Dictionary initializer is C# 6.0 feature whereas collection initializer is available from C# 3.0 onwards.

New is creating a dictionary this way
Dictionary<int, string> myDict = new Dictionary<int, string>() {
[1] = "Pankaj",
[2] = "Pankaj",
[3] = "Pankaj"
};
with the style of <index> = <value>
Obsolete: string indexed member syntax (as stated in the comments)
Dictionary<int, string> myDict = new Dictionary<int, string>() {
$1 = "Pankaj",
$2 = "Pankaj",
$3 = "Pankaj"
};
Taken from A C# 6.0 Language Preview
To understand the $ operator, take a look at the AreEqual function call. Notice the Dictionary member invocation of “$Boolean” on the builtInDataTypes variable—even though there’s no “Boolean” member on Dictionary. Such an explicit member isn’t required because the $ operator invokes the indexed member on the dictionary, the equivalent of calling buildInDataTypes["Boolean"].

Related

Dictionary initializer has different behavior and raises run-time exception when used in combination of array initializer

I have the following C# code which initializes a new dictionary with int keys and List<string> values:
var dictionary =
new Dictionary<int, List<string>>
{
[1] = new List<string> { "str1", "str2", "str3" },
[2] = new List<string> { "str4", "str5", "str6" }
};
If I decompile an executable made from this snippet back to C# the corresponding part looks like this:
Dictionary<int, List<string>> expr_06 = new Dictionary<int, List<string>>();
expr_06[1] = new List<string>
{
"str1",
"str2",
"str3"
};
expr_06[2] = new List<string>
{
"str4",
"str5",
"str6"
};
Everything seems normal and is working properly here.
But when I have the following code:
var dictionary2 =
new Dictionary<int, List<string>>
{
[1] = { "str1", "str2", "str3" },
[2] = { "str4", "str5", "str6" }
};
which again seems like normal code and compiles successfully, but during runtime I get the following exception:
System.Collections.Generic.KeyNotFoundException: 'The given key was not present in the dictionary.'
When I look into the decompiled code of the second example I can see that it is different from the first one:
Dictionary<int, List<string>> expr_6E = new Dictionary<int, List<string>>();
expr_6E[1].Add("str1");
expr_6E[1].Add("str2");
expr_6E[1].Add("str3");
expr_6E[2].Add("str4");
expr_6E[2].Add("str5");
expr_6E[2].Add("str6");
And of course this explains the exception.
So now my questions are:
Is this expected behavior and is it documented somewhere?
Why is the syntax above allowed but the following syntax is not?
List<string> list = { "test" };
Why is the following syntax not allowed then?
var dict = new Dictionary<int, string[]>
{
[1] = { "test1", "test2", "test3" },
[2] = { "test4", "test5", "test6" }
};
Similar but different questions:
What happens under the hood when using array initialization syntax to initialize a Dictionary instance on C#?
How to make inline array initialization work like e.g. Dictionary initialization?
Let me try to answer all of your questions:
Is this expected behavior and is it documented somewhere?
Yes, it is documented in the C# 6.0 Language Specification under sections §7.6.11.2 Object initializers and §7.6.11.3 Collection initializers.
The syntax
var a =
new Test
{
[1] = "foo"
[2] = "bar"
};
was actually newly introduced in C# 6.0 as an extension of the previous object initialization syntax to indexers. An object initializer used together with new (see object creation expression, §7.6.11) always translates to object instantiation and member access of the corresponding object (using a temporary variable), in this case:
var _a = new Test();
_a[1] = "foo";
_a[2] = "bar";
var a = _a;
The collection initializer goes similar besides that each element of the initializer is passed as an argument to the Add method of the newly created collection:
var list = new List<int> {1, 2};
becomes
var _list = new List<int>();
_list.Add(1);
_list.Add(2);
var list = _list;
An object initializer can also contain other object or collection initializers. The specification states for the case of collection initializers:
A member initializer that specifies a collection initializer after the
equals sign is an initialization of an embedded collection. Instead of
assigning a new collection to the target field, property or indexer,
the elements given in the initializer are added to the collection
referenced by the target.
So a sole collection initalizer used within an object initializer will not attempt to create a new collection instance. It will only try to add the elements to an exisiting collection, i.e. a collection that was already instantiated in the constructor of the parent object.
Writing
[1] = new List<string> { "str1", "str2", "str3" }
is actually a totally different case because this is an object creation expression which only contains an collection initializer, but isn't one.
Why is the syntax above allowed but the following
syntax is not?
List<string> list = { "test" };
Now, this is not a collection initializer anymore. A collection initalizer can only occur inside an object initializer or in an object creation expression. A sole { obj1, obj2 } next to an assignment is actually an array initializer (§12.6). The code does not compile since you can't assign an array to a List<string>.
Why is the following syntax not allowed then?
var dict = new Dictionary<int, string[]>
{
[1] = { "test1", "test2", "test3" },
[2] = { "test4", "test5", "test6" }
};
It is not allowed because collection initalizers are only allowed to initialize collections, not array types (since only collections have an Add method).
Using a list-initializer (that is using = { "test1", "test2", "test3" }) assumes the list already was initialized in some way, e.g. in the class´ constructor to something like this:
class MyClass
{
List<string> TheList = new List<string>();
}
Now you can use the list-initializer:
var m = new MyClass { TheList = { myElementsHere } };
As you already showed this is just a shortcut to calling the Add-method.
However in your case the list is not initialized at all making the call to the list-initializer raise the mentioned exception. Just declaring a Dictionary whose values are lists of any type doesn´t mean you already initialized those lists. You have to do this as with any other class before you can call any of its methods (e.g. Add which is just wrapped within the initializer).

Can array indexes be named in C#?

I'm wondering if the index of an array can be given a name in C# instead of the default index value. What I'm basically looking for is the C# equivalent of the following PHP code:
$array = array(
"foo" => "some foo value",
"bar" => "some bar value",
);
Cheers.
PHP blends the concept of arrays and the concept of dictionaries (aka hash tables, hash maps, associative arrays) into a single array type.
In .NET and most other programming environments, arrays are always indexed numerically. For named indices, use a dictionary instead:
var dict = new Dictionary<string, string> {
{ "foo", "some foo value" },
{ "bar", "some bar value" }
};
Unlike PHP's associative arrays, dictionaries in .NET are not sorted. If you need a sorted dictionary (but you probably don't), .NET provides a sorted dictionary type.
In an array, no. However, there is the very useful Dictionary class, which is a collection of KeyValuePair objects. It's similar to an array in that it is an iterable collection of objects with keys, but more general in that the key can be any type.
Example:
Dictionary<string, int> HeightInInches = new Dictionary<string, int>();
HeightInInches.Add("Joe", 72);
HeightInInches.Add("Elaine", 60);
HeightInInches.Add("Michael", 59);
foreach(KeyValuePair<string, int> person in HeightInInches)
{
Console.WriteLine(person.Key + " is " + person.Value + " inches tall.");
}
MSDN Documentation for Dictionary<TKey, TValue>
Look at Hashtable in C#. This is the data structure that does what you want in C#.
You could use a Dictionary<string, FooValue> or similar type or collection type or, if you must stick to array, define an Enum with your labels.

What is this syntax using new followed by a list inside braces?

Ive just seen a piece of code that uses a generic list class to instantiate itself in the following manner:
var foo = new List<string>(){"hello", "goodbye"};
The curly braces after the contructor are especially confusing. It reminds me somewhat of
var bar = new string[]{"hi","bye"};
but in the past i've wouldve always used:
var foo = new List<string>(new []{"hello", "goodbye"});
Has anybody got a link explaining the syntax in the first line of code? I wouldnt even know where to begin with googling it.
As others have pointed out, that is a collection initializer. Some other features you might not be aware of that were added to C# 3:
A collection initializer constructor may omit the parentheses if the argument list is empty. So new List<int> { 10, 20, 30 } is fine.
An array initialized with an array initializer may in some cases omit the type. For example, var myInts = new[] { 10, 20, 30}; infers that myInts is int[].
Objects may be initialized using a similar object initializer syntax. var c = new Customer() { Name = "Fred" }; is the same as var temp = new Customer(); temp.Name = "Fred"; var c = temp;
The point of these features is to (1) make more things that used to require statements into things that require only expressions; LINQ likes things to be expressions, and (2) to enable richer type inference, particularly for anonymous types.
Finally: there has been some confusion in some of the answers and comments regarding what is required for a collection initializer. To be used with a collection initializer the type must (1) implement IEnumerable (so that we know it is a collection) and (2) have an Add method (so that we can add stuff to it.)
See
http://blogs.msdn.com/b/madst/archive/2006/10/10/what-is-a-collection_3f00_.aspx
for additional thoughts on the design of the feature.
here you go. The keyword is "Array Initializers".
http://msdn.microsoft.com/en-us/library/aa664573(v=vs.71).aspx
or rather "Collection Initializers"
http://msdn.microsoft.com/en-us/library/bb384062.aspx
This is a collection initializer: http://msdn.microsoft.com/en-us/library/bb384062.aspx
The type so initialized must implement IEnumerable and have an Add method. The items in the curly-brace list are passed to the add method; different items in the list could be passed to different Add methods. If there's an Add overload with more than one argument, you put the multiple arguments in a comma-separated list enclosed in curly braces.
For example:
class MyWeirdCollection : IEnumerable
{
public void Add(int i) { /*...*/ }
public void Add(string s) { /*...*/ }
public void Add(int i, string s) { /*...*/ }
//IEnumerable implementation omitted for brevity
}
This class could be initialized thus:
var weird = new MyWeirdCollection { 1, "Something", {5, "Something else"} };
This compiles to something like this:
var temp = new MyWeirdCollection();
temp.Add(1);
temp.Add("Something");
temp.Add(5, "Something else");
var weird = temp;
In his blog post (link posted by Eric Lippert in the comments), Mads Torgersen expresses this concisely:
The list you provide is not a “list of elements to add”, but a “list of sets of arguments to Add methods”. ...[W]e do separate overload resolution against Add methods for each entry in the list.
In the third line of code you provided you are making a new string array, and then passing that string array to the list. The list will then add each of those items to the list. This involves the extra overhead of allocating the array, populating it, and then discarding it.
There is a mechanism for a class to define how to use Collection Initializers to populate itself. (See the other answers) I have never found the need to utilize this for my own classes, but existing data structures such as List, Dictionary, often define them, and they are useful to use.
This is a collection initializer. You can use it on collections with an Add method.
The pair of parentheses before the curly braces is optional.
This is very convenient, because you can use it on collections other than lists, for example on dictionaries:
var x = new Dictionary<int,string> {{1, "hello"}, {2, "world"}};
This lets you avoid a lengthier initialization sequence:
var x = new Dictionary<int,string>();
x.Add(1, "hello");
x.Add(2, "world");

Is there a an easier way to initialize a List<KeyValuePair<T, U>>, like a Dictionary<T, U>?

Actually I need something like List<KeyValuePair<T, U>> but I want to be able to initialize it like dictionary (i.e. without writing new KeyValuePair every time). Like this:
Dictionary<string, string> dic = new Dictionary<string, string>
{
{ "key1", "value1"},
{ "key2", "value2"}
};
EDIT: It turns out .NET does have a combination list/dictionary type already: OrderedDictionary. Unfortunately this is a non-generic type, making it rather less attractive in my view. However, it retains the insertion order if you just call Add repeatedly.
It's a little strange as calling Add does not affect entries where a key already exists, whereas using the indexer to add a key/value pair will overwrite a previous association. Basically it doesn't seem like a terribly nice API, and I would personally still avoid it unless your use case exactly matches its behaviour.
No, .NET doesn't have any insertion-order-preserving dictionaries. You could always write your own list-based type with the relevant Add method. This might even be one of the few places I'd consider extending an existing type:
public class KeyValueList<TKey, TValue> : List<KeyValuePair<TKey, TValue>>
{
public void Add(TKey key, TValue value)
{
Add(new KeyValuePair<TKey, TValue>(key, value));
}
}
Then:
var list = new KeyValueList<string, string>
{
{ "key1", "value1"},
{ "key2", "value2"}
};
An alternative is to use composition, but my gut feeling is that this is a reasonable use of inheritance. I can't place why I'm happy in this case but not usually, mind you...
Because you do not have a dictionary you cannot use a dictionary initiailzer. You have a list so you could use a list initializer which will be the closest you could get:
var l = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("key1", "value1"),
new KeyValuePair<string, string>("key2", "value2"),
};
Here's the minimum requirement for you to use dictionary initializer: the class must implement IEnumerable and the class must have a public method Add which takes 2 arguments (where the first argument represents the key and the second argument the value). So you could write a custom class which satisfies those requirements and you will be able to use the syntax you have shown in your question.
The code you have typed works fine - further to Mads Togersen's post about the implementation of collection initialisers, the compiler maps the brace-delimited entries ({"key1", "value1"} above) to an Add method on the collection with the same signature - in this case Dictionary.Add(TKey, TValue).

Literal notation for Dictionary in C#?

I currently have a WebSocket between JavaScript and a server programmed in C#. In JavaScript, I can pass data easily using an associative array:
var data = {'test': 'val',
'test2': 'val2'};
To represent this data object on the server side, I use a Dictionary<string, string>, but this is more 'typing-expensive' than in JavaScript:
Dictionary<string, string> data = new Dictionary<string,string>();
data.Add("test", "val");
data.Add("test2", "val2");
Is there some kind of literal notation for associative arrays / Dictionarys in C#?
You use the collection initializer syntax, but you still need to make a new Dictionary<string, string> object first as the shortcut syntax is translated to a bunch of Add() calls (like your code):
var data = new Dictionary<string, string>
{
{ "test", "val" },
{ "test2", "val2" }
};
In C# 6, you now have the option of using a more intuitive syntax with Dictionary as well as any other type that supports indexers. The above statement can be rewritten as:
var data = new Dictionary<string, string>
{
["test"] = "val",
["test2"] = "val2"
};
Unlike collection initializers, this invokes the indexer setter under the hood, rather than an appropriate Add() method.
While, the dictionary initializer answer is totally correct, there is another approach to this that I would point out (but I might not recommend it). If your goal is to provide terse API usage, you could use anonymous objects.
var data = new { test1 = "val", test2 = "val2"};
The "data" variable is then of an "unspeakable" anonymous type, so you could only pass this around as System.Object. You could then write code that can transform an anonymous object into a dictionary. Such code would rely on reflection, which would potentially be slow. However, you could use System.Reflection.Emit, or System.Linq.Expressions to compile and cache a delegate that would make subsequent calls much faster.
Asp.net MVC APIs use this technique in a number of places that I've seen. A lot of the Html Helpers have overloads that accept either an object or a dictionary. I assume the goal of their API design is the same as what you are after; terse syntax at the method call.
Use Dictionary Literals (C#9 proposal) [rejected] or the new syntax (beginning with C#9)
C#9 introduces a simpler syntax to create initialized Dictionary<TKey,TValue> objects without having to specify either the Dictionary type name or the type parameters. The type parameters for the dictionary are inferred using the existing rules used for array type inference.
// C# 1..8
var x = new Dictionary <string,int> () { { "foo", 4 }, { "bar", 5 }};
// C# 9
var x = ["foo":4, "bar": 5];
This synthax makes the work with dictionaries in C# simpler and removing the redundant code.
You can follow the issue on GitHub (and here is the milestone for C#9).
Edit: This proposal is currently rejected:
[...] We think there are a number of interesting use cases around initializing data, particularly for things like immutable dictionaries. We don't find the existing syntax for initializing a dictionary that onerous, nor do we see it as a frequent pattern in code that would benefit much from a language feature. We thing that the general area of initializing data should be looked at again after we do records and withers. [...]
current milestone:
Note that beginning with C# 9.0, constructor invocation expressions are target-typed. That is, if a target type of an expression is known, you can omit a type name, as the following example shows:
Dictionary<int, List<int>> lookup = new()
{
[1] = new() {1, 2, 3},
[2] = new() {5, 8, 3},
[5] = new() {1, 0, 4}
};
As the preceding example shows, you always use parentheses in a target-typed new expression.
If a target type of a new expression is unknown (for example, when you use the var keyword), you must specify a type name.
MSDN
Using DynamicObject, it is not that difficult to create a simpler dictionary initializer.
Imagine you want to call the following method
void PrintDict(IDictionary<string, object> dict) {
foreach(var kv in dict) {
Console.WriteLine (" -> " + kv.Key + " = " + kv.Value);
}
}
using a literal syntax like
var dict = Dict (Hello: "World", IAm: "a dictionary");
PrintDict (dict);
This can be accomplished by creating a dynamic object like this
dynamic Dict {
get {
return new DynamicDictFactory ();
}
}
private class DynamicDictFactory : DynamicObject
{
public override bool TryInvoke (InvokeBinder binder, object[] args, out object result)
{
var res = new Dictionary<string, object> ();
var names = binder.CallInfo.ArgumentNames;
for (var i = 0; i < args.Length; i++) {
var argName = names [i];
if(string.IsNullOrEmpty(argName)) throw new ArgumentException();
res [argName] = args [i];
}
result = res;
return true;
}
}

Categories