Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a new Dictionary<,> from an IReadOnlyDictionary<,>?

Tags:

c#

dictionary

.NET 4.5 introduces the handy IReadOnlyDictionary<TKey, TValue> interface. A Dictionary<TKey, TValue> is-an IReadOnlyDictionary<TKey, TValue>, so I can just pass the former wherevert the latter is required.

I'm not sure about the opposite way, though: How do I create a new Dictionary<,> based on an existing IReadOnlyDictionary<,>?

  • Dictionary<,> has several constructors that take an IDictionary<,> -- but none that take an IReadOnlyDictionary<,>.
  • IReadOnlyDictionary<,> has an extension method ToDictionary<,>(). However, that's inherited from IEnumerable<>. So to use it, I have to pass two utterly redundant delegates like this: readOnlyDict.ToDictionary(pair => pair.Key, pair => pair.Value). Ugly!
  • Of course, I can always create a new Dictionary<,>, iterate over the original pairs and copy them over.

It seems to me that there should be a trivial way to create a new Dictionary<,> based on an existing IReadOnlyDictionary<,>. Am I missing something?

Edit: Some clarification. I'm not looking for some magic way of treating an IReadOnlyDictionary<,> as a Dictionary<,>. I want to create a new Dictionary<,> that copies its initial values from an IReadOnlyDictionary<,>. This question is a long-winded way of asking:

Dictionary<,> has a convenience constructor to copy the initial values from an IDictionary<,>. How come it doesn't have one taking an IReadOnlyDictionary<,> and what's the most idiomatic way of achieving the same result?

like image 365
Daniel Wolf Avatar asked Feb 23 '15 08:02

Daniel Wolf


People also ask

Does c sharp have Dictionary?

In C#, Dictionary is a generic collection which is generally used to store key/value pairs. The working of Dictionary is quite similar to the non-generic hashtable. The advantage of Dictionary is, it is generic type. Dictionary is defined under System.


3 Answers

Dictionary<TKey, TValue> is able to implement IReadOnlyDictionary<TKey, TValue>, because any code that takes the latter is promising not the modify the dictionary, which is a subset of the functionality the former provides.

But consider the other direction. You start with an IReadOnlyDictionary<TKey, TValue>, and you try to turn it into a regular Dictionary<TKey, TValue>. Now, you've taken something that had previously been promised to not be modified, and turned it into something that may be modified.

Clearly, that just won't do.

Furthermore, you can't just assume that the read-only implementation would throw an exception or something when modified (e.g. run-time safety even though not compile-time safety) because, as you know, you can always get the read-only interface from a mutable implementation.

So to be safe, you have two options:

  1. Just copy the entire dictionary contents into a new object.
  2. Wrap the read-only object in an IDictionary<TKey, TValue> implementation that does throw an exception if you try to modify it.

Note that the latter does not actually give you what you are specifically asking for. It's close, but it's not an actual instance of Dictionary<TKey, TValue>.

In terms of copying, you have many choices. Personally, I think ToDictionary() is itself just fine. But if you really don't like the verbosity, you can wrap it in an extension method:

public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(
    this IReadOnlyDictionary<TKey, TValue> dict)
{
    return dict.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}


Addendum:
It occurs to me that I should probably clarify: the above all assumes you are trying to convert an arbitrary instance of IReadOnlyDictionary<TKey, TValue>. Obviously, if you know or at least suspect that your IReadOnlyDictionary<TKey, TValue> object is in fact an instance of Dictionary<TKey, TValue>, you can cast or attempt to cast (respectively) directly to Dictionary<TKey, TValue>.

like image 138
Peter Duniho Avatar answered Oct 09 '22 22:10

Peter Duniho


You can do this:

Dictionary<string, string> dictionary = readOnlyDictionary
                .Select(dict => dict).ToDictionary(pair => pair.Key, pair => pair.Value);
like image 28
Rans Avatar answered Oct 09 '22 23:10

Rans


It seems that IReadOnlyDictionary<> was added later, and existing classes (such as Dictionary<>) were not retrofitted to support it with new methods, for backward compatibility reasons. [citation needed], though.

For what it's worth, Microsoft's reference implementation of Dictionary's constructor is essentially

Dictionary(IDictionary dictionary)
: this(dictionary.Count) {
    foreach (KeyValuePair<TKey,TValue> pair in dictionary) {
            Add(pair.Key, pair.Value);
    }
}

And Enumerable is essentially

Dictionary<> ToDictionary<>(this IEnumerable<> source, Func<> keySelector, Func<> elementSelector) 
{
    Dictionary<> d = new Dictionary<>();
    foreach (TSource element in source) 
    d.Add(keySelector(element), elementSelector(element));
    return d;
}

So the difference seems to be mainly the calls to the selector delegates.

So an extension method copying the constructor's code but taking a IReadOnlyDictionary<>, more or less as @Steve did, seems slightly simpler and slightly more efficient...

like image 3
Pablo H Avatar answered Oct 09 '22 23:10

Pablo H