我有很多字典,其中键是几个不同值(主要是字符串和整数)的组合。我是否将这些密钥作为类实现(并覆盖GetHashCode()
,Equals()
等),还是使用struct
代替?
ReSharper可以轻松完成覆盖,但代码看起来很糟糕。是否有使用结构的性能影响?
答案 0 :(得分:3)
如果你唯一的问题是定义在Dictionary<TKey,TValue>
中使用的相等性,那么你可以选择另一个路径来实现IEqualityComparer<T>
。这可以手动传递给字典构造函数,并在不修改密钥类型的情况下处理TKey
值的相等比较。
如果您有更复杂的定义复合值相等性的问题,那么我将专注于使复合值本身支持相等。是的,定义平等所需的全套方法是一种痛苦,但它主要是锅炉板代码。正确的做法比锅炉板代码看起来更麻烦更重要。
答案 1 :(得分:1)
我实际上会说,对于任何结构,应始终手动编写Equals()
和GetHashCode()
的覆盖以及实施IEquatable<T>
,如果完全可能的话可以被某人用作关键,所以我当然不会用它来避免这样做。
除了需要装箱之外,默认实现相当慢,因为它使用反射来检查字段。至少在一些框架版本中也存在一个错误(实现非常明智地优化为二进制比较,这样做会得到正确的结果,但不幸的是在这种情况下错误判断,因此两个结构包含等价的{{1 }}字段可能被认为是不相等的。)
当需要快速复合时,除了作为复合键之外,对系统没有任何意义,我建议使用decimal
。 Tuple
可让您轻松撰写这些内容,Tuple.Create()
和Equals()
的覆盖非常合理。
在某些情况下,也可以使用匿名类作为键(仅在给定方法的上下文中),这里GetHashCode()
和Equals()
的覆盖也很合理
答案 2 :(得分:0)
要创建这样的复合类,建议的方法是从Tuple<int, string, ...>
继承。
这样,您不必自己覆盖GetHashCode
和Equals
,基类会为您完成。
您可以轻松地为每个字段提供有意义的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。