2012-06-29 24 views
5

Tôi đang triển khai DoubleEqualityComparer có thể tái sử dụng (với dung sai tùy chỉnh: tham số hàm tạo "epsilon") để giảm bớt việc sử dụng LINQ với các chuỗi kép. Ví dụ:IEqualityComparer <double> với dung sai; làm thế nào để thực hiện GetHashCode?

bool myDoubleFound = doubles.Contains(myDouble, new DoubleEqualityComparer(epsilon: 0.01)); 

Cách thích hợp để triển khai GetHashCode là gì? Dưới đây là các mã:

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: Tôi luôn có thể trả về giá trị tương tự (ví dụ: GetHashCode (double obj) {return 0;}) để luôn luôn buộc các cuộc gọi đến Equals phương pháp (double, double) (không phải là rất biểu diễn, tôi biết), nhưng tôi nhớ rằng giải pháp này gây ra vấn đề khi so sánh được sử dụng với từ điển ...

+8

Bạn không nên làm điều này vì nó vi phạm sự chuyển đổi. Có thể là 'a bằng b' và' b bằng c' nhưng 'a không bằng c'. – Ani

Trả lời

4

Tôi không chắc chắn bằng cách sử dụng EqualityComparer là cách để đi. Bởi vì so sánh các đối tượng không bằng.

Có lẽ bạn nên xem xét sử dụng một Any khoản đơn giản + một phương pháp hữu ích:

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

Cảm ơn, bạn và Ani thuyết phục tôi không sử dụng IEqualityComparer, nhưng để xác định một giao diện tùy chỉnh (và đề ra các biện pháp mở rộng, LINQ-style): public interface ITolerable { bool AreAlmostEqual (T x, T y) ; } IEqualityComparer tiện dụng vì có các phương thức chính thức LINQ sẵn sàng để sử dụng (không gọi GetHashcode), nhưng tôi từ bỏ việc không thực hiện nó là khủng khiếp (và nguy hiểm). – Notoriousxl

1

tôi sẽ ném NotSupportedException trong GetHashCode vì vậy bạn có thể có bánh của bạn và ăn nó quá. Điều này mang đến cho bạn sự tiện lợi khi có một số IEqualityComparer trong LINQ và các phương thức khác, nhưng đảm bảo rằng bất kỳ việc sử dụng nào của GetHashCode đều bị thổi phồng lên. Trong thực tế, bạn có thể thấy rằng cách bạn sử dụng bộ so sánh bình đẳng không bao giờ thực sự yêu cầu GetHashCode để được gọi. Bạn thậm chí có thể gọi lớp học này là NotHashableDoubleEqualityComparer để được siêu rõ ràng về giới hạn đối với người gọi.