如何获得ToDictionary()失败的重复键?

Rob*_*vey 18 c# dictionary duplicates

我正在使用IEnumerable's ToDictionary()扩展方法创建一个Dictionary对象:

var dictionary = new Dictionary<string, MyType>
    (myCollection.ToDictionary<MyType, string>(k => k.Key));
Run Code Online (Sandbox Code Playgroud)

执行时,会抛出以下内容ArgumentException:

已添加具有相同键的项目.

如何让它告诉我重复的密钥是什么?

Guf*_*ffa 16

获取重复的键:

var duplicateKeys =
  myCollection
 .GroupBy(k => k.Key)
 .Where(g => g.Count() > 1)
 .Select(g => g.Key);
Run Code Online (Sandbox Code Playgroud)

  • 似乎奇怪的是`ToDictionary()`抛出的`ArgumentException`不包含失败的密钥.您的查询成本有多高?这个系列非常大. (2认同)
  • @ThomasLevesque:没有理由不抛出新的 ArgumentException("已添加具有相同键的项目。键:" + key.ToString())` 而 ToString() 对每个都没有意义关键,我敢打赌它会消除所有 .NET Framework 开发人员的许多调试工时,几乎没有缺点。 (2认同)

Joe*_*ler 8

如果您的特定情况可以只将一组具有重复Key属性的对象插入到字典中,则可以Distinct在调用之前使用LINQ 方法完全避免此错误ToDictionary.

var dict = myCollection.Distinct().ToDictionary(x => x.Key);
Run Code Online (Sandbox Code Playgroud)

当然,只有当集合中的类重写Equals并且GetHashCode只考虑Key属性时,上述操作才有效.如果不是这种情况,您需要制作IEqualityComparer<YourClass>仅比较Key属性的自定义.

var comparer = new MyClassKeyComparer();
var dict = myCollection.Distinct(comparer).ToDictionary(x => x.Key);
Run Code Online (Sandbox Code Playgroud)

如果您需要确保集合中的所有实例最终都在字典中,那么使用Distinct将不适合您.


pho*_*oog 5

未包含失败的密钥,因为通用字典无法保证密钥类型上存在有意义的ToString方法.您可以创建一个包装类,该类会抛出更具信息性的异常.例如:

//Don't want to declare the key as type K because I assume _inner will be a Dictionary<string, V>
//public void Add(K key, V value)
//
public void Add(string key, V value)
{
    try
    {
        _inner.Add(key, value);
    }
    catch (ArgumentException e)
    {
        throw new ArgumentException("Exception adding key '" + key + "'", e);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Iain`ToString()`的默认实现返回对象类型的名称.如果异常消息说"给定的密钥'{0}'不在字典中",那么消息很可能会说"给定密钥'MyNamespace.MyType'不在字典中".这没有用,因为*该类型的所有*实例都具有相同的字符串表示形式.如果某种类型的保证该类型为ToString提供了更有意义的值,那么这样的消息就有意义了. (3认同)