为什么Dictionary<TKey, TValue>没有一个IEnumerable<KeyValuePair<TKey, TValue>>构造函数?

14

好的,我知道构建一个提供该功能的工厂方法很简单; 但是考虑到 Dictionary<TKey, TValue>IEnumerable<KeyValuePair<TKey, TValue>>,它难道不应该有一个类似于 List<T>ctor(IEnumerable<T> range) 构造函数吗?

更荒谬的是,它提供了一个接受 IDictionary<TKey, TValue> 作为源的构造函数,但由于该接口也是IEnumerable<KeyValuePair<TKey, TValue>>,因此使用 IEnumerable 选项肯定更合理,除非在这个类最初设计时没有 IEnumerable<> 接口。

更糟糕的是,如果你查看 IDictionary 版本的 ctor 实现 - 输入的字典会用以下代码导入:

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

有人能想出一个好的原因,为什么框架设计者在只需要基本接口时选择了最具体的接口吗?

编辑

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

我知道 - 这个测试是反向的 - 但出于某种原因,我认为这更能说明我的观点 :)

鉴于Key比较器不是IDictionary接口的一部分,您永远无法保证导入的字典不会生成重复的键,从而在构建新字典时引发ArgumentException。

因此,您可以使用一个执行相同操作的IEnumerable构造函数。


我最近也为Guava请求了同样的事情:http://code.google.com/p/guava-libraries/issues/detail?id=320 - finnw
2个回答

13

完全是一个非官方的猜测:

如果一个构造函数允许一个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
正如同样的情况越来越多,我们可以看到 Dictionary 也“缺少”一个 AddRange - 或许是出于类似的原因? - AakashM
1
虽然这可能不是官方原因,但足以证明为什么没有 IEnumerable<KeyValuePair<TKey, TValue>> 构造函数的存在。 - Paul Turner
6
+1 那是一个很好的观点 - 也可能非常接近真相。但如果这是设计决策,那么它是有缺陷的:我可以传递一个使用比新的 IComparer(例如默认的 StringComparer 与不区分大小写的 StringComparer)更少限制的 Dictionary<TKey,TValue> 实例,仍然可能生成异常。一个 IDictionary 并不一定能成为另一个 IDictionary。 - Andras Zoltan
3
也许他们应该省略掉接收 IDictionary 和比较器两个参数的构造函数重载。这个问题的架构师现在可能已经被晋升了。:-> - herzmeister
1
@Joe - 当然 - 你是对的;我认为最终应该放弃这个IDictionary ctor - 因为它声称向调用者提供了无法保证的保证。因此,它应该降级为IEnumerable之一,并包括IEqualityComparer重载。对我来说,那是有意义的。与此同时,我将使用工厂方法! - Andras Zoltan
显示剩余4条评论

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接