2010-06-24 5 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(); 
    } 
} 

또한 단지 두 지점 및 일부 다른 부가 요소 인 벡터 클래스를 가지고있다. 내 벡터에 동일한 포인트를 갖고 싶어하지 않는, 그래서 나는이 방법을 함께했다 :

[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); 
    } 

내가 사용 : 나에게 예외를 제공해야합니다

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; 
     } 

그리고이 단위 테스트, 같은 점, 즉 mPoint1, 예외가 throw 된 코드와 같습니다. mPoint2를 사용할 때 이름과 좌표가 같아도 예외는 발생하지 않습니다. 해시 코드를 확인한 결과 사실상 다릅니다. GetHashCode에서 만든 코드를 기반으로이 두 점은 동일한 해시 코드를가집니다.

누군가 내가 왜 그렇게 행동하지 않는지 설명 할 수 있습니까? 내가 잘 설명 모르겠지만, .. 내가 도움을 주셔서 감사합니다 : D를

조지

답변

4

비교하려고하는 유형 내에 IEqualityComparer<T>을 구현하고 있습니다. 이는 매우 이상합니다. 거의 확실하게 IEquatable<T>을 구현하고 대신 Equals(object)을 무시해야합니다. 그건 분명히 당신의 단위 테스트 작업을 만들 것입니다.

IEquatable<T>IEqualityComparer<T>의 차이는 전자는, 말을하는 클래스에 의해 구현된다는 점이다 "나는 같은 유형의 다른 인스턴스와을 자신을 을 비교할 수 있습니다." (이 같은 유형이 아니지만 대개는 같습니다.) 자연 비교가있는 경우에 적합합니다. 예를 들어 string에 의해 선택된 비교는 서수 평등입니다. 정확히 동일한 순서가되어야합니다. char 값.

이제 IEqualityComparer<T>은 다릅니다. 유형의 두 인스턴스를 비교할 수 있습니다. 특정 유형에 대해 여러 가지 구현이있을 수 있으므로 특정 비교가 "자연적인 것"인지 여부는 중요하지 않습니다. 단지 당신의 직업에 적합한 것이어야합니다. 예를 들어, Shape 클래스를 가질 수 있고, 색상, 영역 또는 그와 비슷한 것으로 도형을 비교하는 서로 다른 평등 비교자를 가질 수 있습니다.

+0

설명 주셔서 대단히 감사합니다. 문서가 아니라. 당신이 말하는 것처럼, IEqualityComparer , IEqualityComparer , IEqualityComparer 을 구현할 수 있습니다. 감사합니다. –

+0

@ 조지 : 주목할 가치가있는 한 가지 점은 평등 비교자는 다른 값을 비교하는 것보다 * 다른 *을 할 의도가 거의 없다는 것입니다. 그것은 대개 자신의 책임이어야합니다. –

1

당신은뿐만 아니라 Object.Equals를 오버라이드 (override) 할 필요가있다. 나는 다음 첫 번째를 사용하는 다른 구현을 재 작업 것

// 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

답장을 보내 주셔서 감사합니다. 그것은 나를 위해 정리했다. –

1

"평등"개념에 대해 다시 생각해 볼 필요가 있습니다. 이는 현재 .NET을 만나는 것이 아니기 때문에 frameworkrequirements입니다.

가능한 모든 경우, 간단한 참조 동등성을 사용할 수 있도록 기념 점 개체 저장소 (이름이 키 가능)로 다시 디자인하는 것이 좋습니다.

+0

안녕하세요 스티븐. 나는 그것을 조사 할 것이다. 나를 지적 해 주셔서 고마워요. –

1

여기에 arcobjects 태그를 넣었으므로 IRelationalOperator.Equals을 언급했을 것입니다.이 메소드가 Geometry의 공간 참조의 클러스터 허용 한계를 준수 하는지를 테스트 한 적이 한 번도 없습니다. ISpatialReferenceTolerance.XYTolerance을 사용하여 조정할 수 있습니다.

+0

안녕 커크! 여기서 보니 반갑다. 나는 이것을 IEquatable 으로 처리했다. 내 클래스는 이름, GPS 정밀도 등과 같은 다른 속성을 가진 IPoint의 래퍼입니다. AOL에서 처리하도록하자면 IRelationalOperator.Equals를 사용해 보겠습니다. 조지 –