我正在实现一个可重用的 DoubleEqualityComparer(具有自定义容差:“epsilon”构造函数参数),以简化 LINQ 与 double 序列的使用。例如:
bool myDoubleFound = doubles.Contains(myDouble, new DoubleEqualityComparer(epsilon: 0.01));
实现 GetHashCode 的正确方法是什么?这是代码:
public class DoubleEqualityComparer : IEqualityComparer<double>, IEqualityComparer<double?>
{
private readonly double epsilon;
public DoubleEqualityComparer(double epsilon)
{
if (epsilon < 0)
{
throw new ArgumentException("epsilon can't be negative", "epsilon");
}
this.epsilon = epsilon;
}
public bool Equals(double x, double y)
{
return System.Math.Abs(x - y) < this.epsilon;
}
public int GetHashCode(double obj)
{
// ?
}
}
PS:我总是可以返回相同的值(例如:GetHashCode(double obj){ return 0; })以始终强制调用 Equals(double, double) 方法(我知道性能不是很好),但我记得当比较器与字典一起使用时,此解决方案会出现问题...
我不确定使用
IEqualityComparer<T>
是正确的方法。因为比较的对象不相等。
也许你应该考虑使用一个简单的
Any
子句 + 实用方法:
private static bool DoublesAreNearlyEquals(double d1, double d2, double epsilon = 0.01D)
{
return System.Math.Abs(d1 - d2) < this.epsilon;
}
private void foo()
{
var myDoubles = Getdoubles();
var doubleToSearch = 42D;
var result = myDoubles.Any(d=>DoublesAreNearlyEquals(d, doubleToSearch));
}
我会把
NotSupportedException
扔进GetHashCode
,这样你就可以鱼与熊掌兼得。 这为您提供了在 LINQ 和其他方法中使用 IEqualityComparer
的便利,但保证了 GetHashCode
的任何使用都会爆炸。 在实践中,您可能会发现使用相等比较器的方式实际上从来不需要调用 GetHashCode
。 您甚至可以将此类称为 NotHashableDoubleEqualityComparer
以非常清楚对调用者的限制。
您可以实现只需要
IEqualityComparer<T>
的 GetHashCode()
,而不是实现需要 IComparer<T>
的 int Compare(T? x, T? y)
。
请注意,
SortedDictionary<T>
和SortedSet<T>
都有一个接受IComparer<T>
参数的构造函数重载。