为什么词典没有AddRange?

标题足够基本,为什么我不能:

Dictionary<string, string> dic = new Dictionary<string, string>(); dic.AddRange(MethodThatReturnAnotherDic()); 

对原始问题的评论总结得非常好:

因为从来没有人devise,规定,实施,testing,logging和发运该function。 – @Gabe Moothart

至于为什么? 那么,可能是因为合并字典的行为不能以符合框架指南的方式推理。

AddRange不存在,因为范围对关联容器没有任何意义,因为数据范围允许重复条目。 例如,如果您有一个IEnumerable<KeyValuePair<K,T>>该集合不防止重复的条目。

添加键值对的集合,甚至合并两个字典的行为是直接的。 但是,如何处理多个重复条目的行为却不是。

方法处理重复时应该是什么样的行为?

至less有三个我能想到的解决scheme:

  1. 一个重复的条目抛出exception
  2. 抛出一个包含所有重复条目的exception
  3. 忽略重复项

当抛出exception时,原始字典的状态应该是什么?

Add几乎总是作为一个primefaces操作来实现:成功并更新集合的状态,或者失败,并且集合的状态保持不变。 由于AddRange可能由于重复的错误而失败,保持其行为与Add一致的方式也是通过在任何重复上抛出exception来使其成为primefaces的,并保持原始字典的状态不变。

作为一个API消费者,需要迭代地去除重复的元素,这意味着AddRange应该抛出一个包含所有重复值的exception。

然后,select归结为:

  1. 抛出所有重复的exception,只留下原始字典。
  2. 忽略重复项并继续。

有支持这两种用例的论据。 要做到这一点,你添加一个IgnoreDuplicates标志的签名?

IgnoreDuplicates标志(当设置为true时)也将提供显着的加速,因为底层实现将绕过用于重复检查的代码。

所以现在,你有一个标志允许AddRange支持这两种情况,但是有一个没有logging的副作用(这是框架devise师真正努力避免的)。

概要

由于在处理重复数据时没有明确的,一致的和预期的行为,因此不容易将它们全部处理在一起,也不提供开始的方法。

如果您发现自己不断地需要合并词典,那么当然可以编写自己的扩展方法来合并词典,这些词典的行为方式可以适用于您的应用程序。

我find了解决办法:

 Dictionary<string, string> mainDic = new Dictionary<string, string>() { { "Key1", "Value1" }, { "Key2", "Value2.1" }, }; Dictionary<string, string> addDic = new Dictionary<string, string>() { { "Key2", "Value2.2" }, { "Key3", "Value3" }, }; mainDic.AddRangeOverride(addDic); // Overrides all existing keys // or mainDic.AddRangeNewOnly(addDic); // Adds new keys only // or mainDic.AddRange(additionalDic); // Throws an error if keys already exist // or if (!mainDic.ContainsKeys(additionalDic.Keys)) // Checks if keys don't exist { mainDic.AddRange(additionalDic); } 

 namespace MyProject.Helper { public static void AddRangeOverride<TKey, TValue>(this Dictionary<TKey, TValue> dic, Dictionary<TKey, TValue> dicToAdd) { dicToAdd.ForEach(x => dic[x.Key] = x.Value); } public static void AddRangeNewOnly<TKey, TValue>(this Dictionary<TKey, TValue> dic, Dictionary<TKey, TValue> dicToAdd) { dicToAdd.ForEach(x => { if (!dic.ContainsKey(x.Key)) dic.Add(x.Key, x.Value); }); } public static void AddRange<TKey, TValue>(this Dictionary<TKey, TValue> dic, Dictionary<TKey, TValue> dicToAdd) { dicToAdd.ForEach(x => dic.Add(x.Key, x.Value)); } public static bool ContainsKeys<TKey, TValue>(this Dictionary<TKey, TValue> dic, IEnumerable<TKey> keys) { bool result = false; keys.ForEachOrBreak((x) => { result = dic.ContainsKey(x); return result; }); return result; } public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) { foreach (var item in source) action(item); } public static void ForEachOrBreak<T>(this IEnumerable<T> source, Func<T, bool> func) { foreach (var item in source) { bool result = func(item); if (result) break; } } } 

玩的开心。

我的猜测是缺乏正确的输出到用户发生了什么事。 由于字典中不能有重复键,所以如何处理将两个字典合并在一起的字典? 当然你可以说:“我不在乎”,但是这违背了返回错误/抛出重复键例外的惯例。

你可以做到这一点

 Dictionary<string, string> dic = new Dictionary<string, string>(); // dictionary other items already added. MethodThatReturnAnotherDic(dic); public void MethodThatReturnAnotherDic(Dictionary<string, string> dic) { dic.Add(.., ..); } 

或使用列表添加和/或使用上面的模式。

 List<KeyValuePair<string, string>> 

如果有人像我一样遇到这个问题 – 可以通过使用IEnumerable扩展方法来实现“AddRange”:

 var combined = dict1.Union(dict2) .GroupBy(kvp => kvp.Key) .Select(grp => grp.First()) .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); 

结合字典的主要技巧是处理重复键。 在上面的代码中是部分。select.Select(grp => grp.First()) 。 在这种情况下,它只需从重复组中的第一个元素,但是如果需要,您可以在其中实现更复杂的逻辑。

如果你正在处理w /一个新的Dictionary(并且你没有现有的行丢失),你总是可以从另一个对象列表中使用ToDictionary()。

所以,就你而言,你会做这样的事情:

 Dictionary<string, string> dic = new Dictionary<string, string>(); dic = SomeList.ToDictionary(x => x.Attribute1, x => x.Attribute2); 

如果你知道你不会有重复的密钥,你可以这样做:

 dic = dic.Union(MethodThatReturnAnotherDic()).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); 

如果有重复的键/值对,它将引发exception。

我不知道为什么这不在框架内; 应该。 没有不确定性 只是抛出一个exception。 在这个代码的情况下,它确实会抛出一个exception。