Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't Dictionary<TKey, TValue> have an IEnumerable<KeyValuePair<TKey, TValue>> ctor?

Tags:

.net

generics

Okay - so I know it's simple to build a factory method that provides the functionality; but given that Dictionary<TKey, TValue> is IEnumerable<KeyValuePair<TKey, TValue>>, shouldn't it have a Ctor equivalent to, for example, List<T>'s ctor(IEnumerable<T> range)?

It's even sillier given that it provides a Ctor that takes an IDictionary<TKey, TValue> as a source, but since that interface is also IEnumerable<KeyValuePair<TKey, TValue>>, the IEnumerable option would surely have made more sense; unless the IEnumerable<> interface wasn't around when the class first designed.

It get's worse because if you look at the implementation of the IDictionary version of the ctor - the input dictionary is imported with the following code:

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

Anyone think of a good reason for why the framework designers chose the most specific interface when a base interface was all that was required?

Edit

@Mark Seeman suggests that it's to avoid Exceptions being raised by duplicate keys - which is probably close to the truth - but consider this example:

[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void How_To_Break_The_IDictionary_Ctor_Design_Decision()
{
  Dictionary<string, string> dictionary = new Dictionary<string, string>();
  dictionary.Add("hello", "world");
  dictionary.Add("Hello", "world");

  Dictionary<string, string> dictionary2 = 
    new Dictionary<string, string>(dictionary,
                                   StringComparer.CurrentCultureIgnoreCase);
}

I know - the test's in reverse - but for some reason I thought it made my point better :)

Given that the Key comparer is not part of the IDictionary interface, you can never guarantee that the dictionary you're importing will not generate duplicate keys, and therefore an ArgumentException, in constructing the new one.

Ergo - you might as well just have an IEnumerable constructor that does the same thing.

like image 731
Andras Zoltan Avatar asked Feb 12 '10 15:02

Andras Zoltan


1 Answers

Totally unofficial guess:

If a constructor allowed an IEnumerable<KeyValuePair<TKey, TValue>> you would have been able to supply multiple items with the same key and what would be the expected behavior of that?

E.g. you could have done something like this:

var kvps = new[]
{
    new KeyValuePair<int, string>(1, "Foo"),
    new KeyValuePair<int, string>(1, "Bar"),
    new KeyValuePair<int, string>(1, "Baz")        
}
var dic = new Dictionary<int, string>(kvps);

You could argue that this should simply throw an exception to be consistent with the behavior of the Add method, but I would guess that the design team thought it would be a greater source of confusion than actually useful...

like image 157
Mark Seemann Avatar answered Oct 21 '22 00:10

Mark Seemann