4

我有很多字典,其中的键是几个不同值(主要是字符串和整数)的组合。我是将这些键实现为类(和 overrideGetHashCode()Equals())还是struct改用?

ReSharper 使覆盖变得容易,但代码看起来很糟糕。改用结构是否有任何性能影响?

4

3 回答 3

3

如果您唯一的问题是定义在 a 中使用的相等性,Dictionary<TKey,TValue>那么您可以选择的另一条路径是实现IEqualityComparer<T>. 这可以手动传递给字典构造函数,并在TKey不修改键类型的情况下处理值的相等比较。

如果您在为复合值定义相等性时遇到更普遍的问题,那么我将专注于使复合值本身支持相等性。是的,定义平等所需的全套方法很痛苦,但它主要是样板代码。做对比样板代码看起来是否混乱更重要。

于 2010-03-15T15:33:59.853 回答
1

我实际上会说,对于任何结构,都应该始终手动编写覆盖Equals()GetHashCode()与实现一起编写IEquatable<T>,如果它很可能被某人用作键,那么我当然不会为了避免这样做而使用它.

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

当需要一个除了作为复合键之外对系统没有任何意义的快速复合时,我建议使用Tuple. Tuple.Create()使组合它们变得容易,并且对 和 的覆盖Equals()非常GetHashCode()合理。

在某些情况下,也可以使用匿名类作为键(当然只在给定方法的上下文中),这里对Equals()and的覆盖GetHashCode()也很合理。

于 2012-01-04T16:32:26.477 回答
0

要创建这样一个复合类,推荐的技术是继承自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。

于 2013-07-02T10:20:12.303 回答