2012-06-29 8 views
5

Я реализую многоразовый DoubleEqualityComparer (с пользовательским допуском: параметр конструктора «epsilon»), чтобы облегчить использование LINQ с последовательностями double. Например:IEqualityComparer <double> с допуском; как реализовать GetHashCode?

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 (двойной объект) {вернуться 0;}) всегда заставляют вызов Equals (двойной двойной,) метод (не очень я знаю), но я помню, что это решение вызывает проблемы, когда сравнение используется со словарем ...

+8

Вы не должны этого делать, потому что это нарушает транзитивность. Возможно, что 'a равно b' и' b равно c', но 'a не равно c'. – Ani

ответ

4

Я не уверен, что использование EqualityComparer - это путь. Потому что сравниваемые объекты не равны.

Может быть, вы должны рассмотреть вопрос об использовании простой 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)); 
} 
+1

Спасибо, вы и Ани убедили меня не использовать IEqualityComparer, но определить пользовательский интерфейс (и его набор методов расширения, LINQ-стиль): общедоступный интерфейс ITolerable { BOOL AreAlmostEqual (Т х, Т у) ; } IEqualityComparer был удобен, потому что есть официальные методы LINQ, готовые к использованию (которые не вызывают GetHashcode), но я не знал, что это не реализовано, было ужасно (и опасно). – Notoriousxl

1

Я бы бросить NotSupportedException в GetHashCode, так что вы можете иметь свой кусок пирога и съесть его. Это дает вам возможность иметь IEqualityComparer в LINQ и других методах, но гарантирует, что любое использование GetHashCode взрывается. На практике вы можете обнаружить, что способ использования сопоставления равенства никогда не требует вызова GetHashCode. Вы можете даже назвать этот класс NotHashableDoubleEqualityComparer, чтобы быть предельно ясным об ограничении для вызывающих.