Почему словарь <TKey, TValue> не имеет IEnumerable <KeyValuePair <TKey, TValue >> ctor?

Хорошо - поэтому я знаю, что просто создать метод factory, который обеспечивает функциональность; но при условии, что Dictionary<TKey, TValue> есть IEnumerable<KeyValuePair<TKey, TValue>>, не должен ли он иметь эквивалент Ctor, например, List<T> ctor(IEnumerable<T> range)?

Это еще глупее, поскольку он предоставляет Ctor, который принимает IDictionary<TKey, TValue> как источник, но поскольку этот интерфейс также IEnumerable<KeyValuePair<TKey, TValue>>, опция IEnumerable, несомненно, имела бы больше смысла; если интерфейс IEnumerable<> не был вокруг, когда первый класс был разработан.

Ухудшается, потому что если вы посмотрите на реализацию версии IDictionary ctor - входной словарь импортируется с помощью следующего кода:

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

Кто-нибудь думает о хорошей причине, почему дизайнеры фреймворков выбрали наиболее специфический интерфейс, когда базовый интерфейс был всем, что требовалось?

Edit

@Mark Seeman предполагает, что он должен избегать исключений, возникающих дублирующимися ключами, что, вероятно, близко к истине, но рассмотрим этот пример:

[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);
}

Я знаю - тест в обратном порядке - но почему-то я думал, что это улучшило мою точку зрения:)

Учитывая, что компаратор ключей не является частью интерфейса IDictionary, вы никогда не сможете гарантировать, что словарь, который вы импортируете, не будет генерировать повторяющиеся ключи и, следовательно, ArgumentException при построении нового.

Ergo - вы можете просто иметь конструктор IEnumerable, который делает то же самое.

Ответы

Ответ 1

Полностью неофициальное предположение:

Если конструктор разрешил IEnumerable<KeyValuePair<TKey, TValue>>, вы могли бы предоставить несколько элементов с одним и тем же ключом и каково было бы ожидаемое поведение этого?

например. вы могли бы сделать что-то вроде этого:

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);

Вы можете утверждать, что это должно просто исключать исключение, чтобы оно соответствовало поведению метода Add, но я бы предположил, что команда разработчиков подумала, что это будет большим источником путаницы, чем действительно полезно...

Ответ 2

  public static Dictionary<T, U> ToDictionary(
      this IEnumerable<KeyValuePair<T, U>> source)
  {
    return source.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
  }