首页 文章

字典中的复合键;覆盖GetHashCode(),Equals等或使用结构?

提问于
浏览
4

我有很多字典,其中键是几个不同值(主要是字符串和整数)的组合 . 我是否将这些键实现为类(并覆盖 GetHashCode()Equals() 等)或者我是否使用 struct

ReSharper可以轻松完成覆盖,但代码看起来很糟糕 . 是否有使用结构的性能影响?

3 回答

  • 3

    如果您唯一的问题是在 Dictionary<TKey,TValue> 中定义使用的相等性,那么您可以选择的另一个路径是实现 IEqualityComparer<T> . 这可以手动传递给字典构造函数,并负责 TKey 值的相等比较,而无需修改密钥类型 .

    如果您有更复杂的定义复合值相等性的问题,那么我将专注于使复合值本身支持相等 . 是的,定义平等所需的全套方法是一种痛苦,但它主要是锅炉板代码 . 正确的做法比锅炉板代码看起来更麻烦更重要 .

  • 0

    我实际上会说,对于任何结构,应该总是手动编写 Equals()GetHashCode() 的覆盖以及实现 IEquatable<T> ,如果它's at all likely that it could be used by someone as a key, so I certainly wouldn' t使用它只是为了避免这样做 .

    除了需要装箱之外,默认实现相当慢,因为它使用反射来检查字段 . 至少在一些框架版本中也存在一个错误(实现非常明智地优化为二进制比较,这样做会得到正确的结果,但不幸的是,在这种情况下错误判断,因此两个结构包含等效的 decimal 字段可能被视为不平等) .

    当需要快速复合时,建议不要使用 Tuple . Tuple.Create() 可以轻松编写它们, Equals()GetHashCode() 的覆盖非常合理 .

    在某些情况下,它也适合使用匿名类作为键(当然只在给定方法的上下文中),这里 Equals()GetHashCode() 的覆盖也是非常合理的 .

  • 1

    要创建这样的复合类,推荐的技术是从 Tuple<int, string, ...> 继承 .

    这样,您不必自己覆盖 GetHashCodeEquals ,基类会为您完成 .

    您可以轻松地为每个字段提供有意义的get访问器 .

    public class CompositeKey : Tuple<string, int>
    {
        public CompositeKey(string name, int age)
            : base(name, age)
        {
        }
        public string Name { get { return Item1; } }
        public int Age { get { return Item2; } }
    }
    

    这也强制了不变性,这适用于字典键 .

    至于性能,内置元组非常快 . 我发现自定义结构可以更快,但如果你真的需要每一个额外的性能,最好是直接将你的关键数据编码为int或long .

相关问题