I'm implementing a reusable DoubleEqualityComparer (with a custom tolerance: the "epsilon" constructor parameter) to ease the usage of LINQ with sequences of double. For example:
我正在实现一个可重用的DoubleEqualityComparer(具有自定义的容错:“epsilon”构造函数参数),以简化双精度序列LINQ的使用。例如:
bool myDoubleFound = doubles.Contains(myDouble, new DoubleEqualityComparer(epsilon: 0.01));
What is the right way to implement GetHashCode? Here's the code:
实现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: I can always return the same value (ex: GetHashCode(double obj){ return 0; }) to always force the call to Equals(double, double) method (not very performant, I know), but I remember that this solution causes problems when the comparer is used with a dictionary...
PS:我总是可以返回相同的值(例如:GetHashCode(double obj){return 0;})总是强制调用Equals(double, double)方法(我知道它的性能不是很好),但是我记得当比较器与字典一起使用时,这种方法会导致问题……
2 个解决方案
#1
5
I'm not sure using EqualityComparer is the way to go. Because compared objects are not equals.
我不确定使用EqualityComparer是否合适。因为比较对象不是相等的。
Maybe you should consider using a simple Any
clause + an utility method :
也许你应该考虑使用一个简单的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));
}
#2
1
I would throw NotSupportedException
in GetHashCode
so you can have your cake and eat it too. This gives you the convenience of having an IEqualityComparer
in LINQ and other methods, but guarantees that any usage of GetHashCode
blows up. In practice, you might find that the way you use the equality comparer never actually requires GetHashCode
to be called. You might even call this class NotHashableDoubleEqualityComparer
to be super clear about the limitation to callers.
我会在GetHashCode中加入NotSupportedException,这样你就可以吃你的蛋糕了。这为您提供了在LINQ和其他方法中使用IEqualityComparer的便利,但是保证了GetHashCode的任何使用都会失败。在实践中,您可能会发现使用相等比较器的方式实际上从来不需要调用GetHashCode。您甚至可以调用这个类nothhabledoubleequalitycomparer来超级清楚地说明调用者的限制。
#1
5
I'm not sure using EqualityComparer is the way to go. Because compared objects are not equals.
我不确定使用EqualityComparer是否合适。因为比较对象不是相等的。
Maybe you should consider using a simple Any
clause + an utility method :
也许你应该考虑使用一个简单的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));
}
#2
1
I would throw NotSupportedException
in GetHashCode
so you can have your cake and eat it too. This gives you the convenience of having an IEqualityComparer
in LINQ and other methods, but guarantees that any usage of GetHashCode
blows up. In practice, you might find that the way you use the equality comparer never actually requires GetHashCode
to be called. You might even call this class NotHashableDoubleEqualityComparer
to be super clear about the limitation to callers.
我会在GetHashCode中加入NotSupportedException,这样你就可以吃你的蛋糕了。这为您提供了在LINQ和其他方法中使用IEqualityComparer的便利,但是保证了GetHashCode的任何使用都会失败。在实践中,您可能会发现使用相等比较器的方式实际上从来不需要调用GetHashCode。您甚至可以调用这个类nothhabledoubleequalitycomparer来超级清楚地说明调用者的限制。