Почему словарь <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);
}