2010-06-24 57 views
0

看看这个类:的IEqualityComparer和怪异的结果

public class MemorialPoint:IMemorialPoint,IEqualityComparer<MemorialPoint> 
{ 
    private string _PointName; 
    private IPoint _PointLocation; 
    private MemorialPointType _PointType; 

    private DateTime _PointStartTime; 
    private DateTime _PointFinishTime; 

    private string _NeighborName; 

    private double _Rms; 
    private double _PointPdop; 
    private double _PointHdop; 
    private double _PointVdop; 

    // getters and setters omitted 

    public bool Equals(MemorialPoint x, MemorialPoint y) 
    { 
     if (x.PointName == y.PointName) 
      return true; 
     else if (x.PointName == y.PointName && x.PointLocation.X == y.PointLocation.X && x.PointLocation.Y == y.PointLocation.Y) 
      return true; 
     else 
      return false; 
    } 

    public int GetHashCode(MemorialPoint obj) 
    { 
     return (obj.PointLocation.X.ToString() + obj.PointLocation.Y.ToString() + obj.PointName).GetHashCode(); 
    } 
} 

我也有一个Vector类,它只是两个点和其他一些atributes。我不希望在我的矢量有相同的分数,所以我想出了这个方法:

public void RecalculateVector(IMemorialPoint fromPoint, IMemorialPoint toPoint, int partIndex) 
     { 
      if (fromPoint.Equals(toPoint)) 
       throw new ArgumentException(Messages.VectorWithEqualPoints); 

      this.FromPoint = FromPoint; 
      this.ToPoint = ToPoint; 
      this.PartIndex = partIndex; 

      // the constructDifference method has a weird way of working: 
      // difference of Point1 and Point 2, so point2 > point1 is the direction 
      IVector3D vector = new Vector3DClass(); 
      vector.ConstructDifference(toPoint.PointLocation, fromPoint.PointLocation); 

      this.Azimuth = MathUtilities.RadiansToDegrees(vector.Azimuth); 

      IPointCollection pointCollection = new PolylineClass(); 
      pointCollection.AddPoint(fromPoint.PointLocation, ref _missing, ref _missing); 
      pointCollection.AddPoint(toPoint.PointLocation, ref _missing, ref _missing); 

      this._ResultingPolyline = pointCollection as IPolyline; 
     } 

而这个单元测试,这应该给我一个例外:

[TestMethod] 
    [ExpectedException(typeof(ArgumentException), Messages.VectorWithEqualPoints)] 
    public void TestMemoriaVector_EqualPoints() 
    { 
     IPoint p1 = PointPolygonBuilder.BuildPoint(0, 0); 
     IPoint p2 = PointPolygonBuilder.BuildPoint(0, 0); 

     IMemorialPoint mPoint1 = new MemorialPoint("teste1", p1); 
     IMemorialPoint mPoint2 = new MemorialPoint("teste1", p2); 

     Console.WriteLine(mPoint1.GetHashCode().ToString()); 
     Console.WriteLine(mPoint2.GetHashCode().ToString()); 

     vector = new MemorialVector(mPoint1, mPoint1, 0); 
    } 

当我使用同样的一点,就是mPoint1,就像在代码中抛出异常一样。当我使用mPoint2时,即使它们的名称和坐标相同,也不会抛出异常。我检查了他们的哈希码,他们实际上是不同的。基于我在GetHashCode中创建的代码,我认为这两点将具有相同的哈希码。

有人可以向我解释为什么这不起作用,因为我会这样做吗?我不知道我解释这口井,但..我欣赏的帮助:d

乔治

回答

4

你正在实施IEqualityComparer<T>它试图比较的类型 - 这是非常奇怪的。您几乎可以肯定只是实施IEquatable<T>而不是替代Equals(object)。这绝对会让你的单元测试工作。

IEquatable<T>IEqualityComparer<T>之间的区别是,前者是由一个类实现地说,“我可以与同类型的其他实例比较自己”。 (它不是是同一类型,但它通常是。)如果有一个自然比较 - 例如,由string选择的比较是序数相等 - 它必须是完全相同的序列值为char

现在IEqualityComparer<T>是不同的 - 它可以比较任何两个类型的实例。对于一个给定的类型,可以有多种不同的实现方式,因此无论某个特定的比较是否是“自然的”比较都无关紧要 - 它只是适合您的工作。例如,你可以有一个Shape类,不同的相等比较器可以通过颜色,面积或类似的东西来比较形状。

+0

非常感谢您的解释。这不在文档上。正如你所说,我可以实现IEqualityComparer ,IEqualityComparer ,IEqualityComparer 如果这是目标。 谢谢 – 2010-06-24 16:05:53

+0

@George:有一件值得注意的事情是,平等比较器很少会做任何事情*其他*比比较其他值。这通常应该是他们自己的责任。 – 2010-06-24 16:20:45

1

你需要重写Object.Equals为好。

添加到您的实现:

// In MemorialPoint: 
public override bool Equals(object obj) 
{ 
    if (obj == null || GetType() != obj.GetType()) 
     return false; 

    MemorialPoint y = obj as MemorialPoint; 

    if (this.PointName == y.PointName) 
     return true; 
    else if (this.PointName == y.PointName && this.PointLocation.X == y.PointLocation.X && this.PointLocation.Y == y.PointLocation.Y) 
     return true; 
    else 
     return false; 
} 

我再返工你的其他的方案中使用第一,再加上添加相应的null检查。

public bool Equals(MemorialPoint x, MemorialPoint y) 
{ 
    if (x == null) 
     return (y == null); 
    return x.Equals(y); 
} 
+0

谢谢你的答案。这清理了我。 – 2010-06-24 16:06:11

1

您还需要重新考虑“平等”的概念,因为它目前不符合.NET frameworkrequirements

如果可能的话,我建议重新设计一个纪念点对象(可能用名字键入)的存储库,以便可以使用简单的引用等式。

+0

你好斯蒂芬。我会检查一下。感谢您为我指出了这一点。 – 2010-06-24 16:18:05

1

你已经把一个arcobjects标签,所以我只是想我会提到IRelationalOperator.Equals。我从来没有测试过,看看这种方法是否符合几何体空间参考的集群公差。这可以使用ISpatialReferenceTolerance.XYTolerance进行调整。

+0

你好柯克!很高兴在这里见到你。 我设法用IEquatable 来做到这一点。我的课是IPoint与其他属性的包装,如名称,GPS精度等。 我会给IRelationalOperator.Equals一个尝试,毕竟它让AO更好地处理这个问题。 George – 2010-06-26 13:55:59