Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create a new instance of ImmutableDictionary?

I would like to write something like this:

var d = new ImmutableDictionary<string, int> { { "a", 1 }, { "b", 2 } }; 

(using ImmutableDictionary from System.Collections.Immutable). It seems like a straightforward usage as I am declaring all the values upfront -- no mutation there. But this gives me error:

The type 'System.Collections.Immutable.ImmutableDictionary<TKey,TValue>' has no constructors defined

How I am supposed to create a new immutable dictionary with static content?

like image 969
Lukáš Lánský Avatar asked Jun 04 '14 09:06

Lukáš Lánský


People also ask

What is ImmutableDictionary?

An ImmutableDictionary has methods to modify it like Add or Remove , but they will create a new dictionary and return that, the original one remains unchanged and the copy of the new immutable dictionary is returned.

Is ImmutableDictionary thread safe?

If you need an immutable dictionary use ImmutableDictionary , which is just thread-safe as side-effect (if you can't modify the original instance there is no multi-threading issue).

What is immutable collection in C#?

ImmutableArray. Provides methods for creating an array that is immutable; meaning it cannot be changed once it is created. NuGet package: System.Collections.Immutable (about immutable collections and how to install)


2 Answers

Either create a "normal" dictionary first and call ToImmutableDictionary (as per your own answer), or use ImmutableDictionary<,>.Builder:

var builder = ImmutableDictionary.CreateBuilder<string, int>(); builder.Add("a", 1); builder.Add("b", 2); var result = builder.ToImmutable(); 

It's a shame that the builder doesn't have a public constructor as far as I can tell, as it prevents you from using the collection initializer syntax, unless I've missed something... the fact that the Add method returns void means you can't even chain calls to it, making it more annoying - as far as I can see, you basically can't use a builder to create an immutable dictionary in a single expression, which is very frustrating :(

like image 45
Jon Skeet Avatar answered Sep 17 '22 13:09

Jon Skeet


You can't create immutable collection with a collection initializer because the compiler translates them into a sequence of calls to the Add method. For example if you look at the IL code for var d = new Dictionary<string, int> { { "a", 1 }, { "b", 2 } }; you'll get

IL_0000: newobj instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::.ctor() IL_0005: dup IL_0006: ldstr "a" IL_000b: ldc.i4.1 IL_000c: callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::Add(!0, !1) IL_0011: dup IL_0012: ldstr "b" IL_0017: ldc.i4.2 IL_0018: callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::Add(!0, !1) 

Obviously this violates the concept of immutable collections.

Both your own answer and Jon Skeet's are ways to deal with this.

// lukasLansky's solution var d = new Dictionary<string, int> { { "a", 1 }, { "b", 2 } }.ToImmutableDictionary();  // Jon Skeet's solution var builder = ImmutableDictionary.CreateBuilder<string, int>(); builder.Add("a", 1); builder.Add("b", 2);    var result = builder.ToImmutable(); 
like image 104
Dirk Avatar answered Sep 20 '22 13:09

Dirk