2010-02-07 3 views
2

저는 C#을 처음 사용합니다. 아마도 IEquatable을 올바르게 구현하지 않을 것입니다. 내 유형의 객체는 동일하게 간주되어야하기 때문입니다.C# XNA : 사전에 문제가 발생했습니다.

는 클래스

을 :

class CompPoint : IComparable { 
     public int X; 
     public int Y; 

     public CompPoint(int X, int Y) { 
      this.X = X; 
      this.Y = Y; 
     } 

    public override bool Equals(Object o) { 
     if (!(o is CompPoint)) { 
      throw new ArgumentException(String.Format("argument is not a CompPoint (%s given)", o)); 
     } 
     CompPoint cp = (CompPoint)o; 

     return this.X == cp.X && this.Y == cp.Y; 
    } 

    public override int GetHashCode() { 
     int hash = base.GetHashCode(); // this is a problem. replace with a constant? 
     hash = (hash * 73) + this.X.GetHashCode(); 
     hash = (hash * 73) + this.Y.GetHashCode(); 
     return hash; 
    } 
} 

(. 그것은 클래스 인 정당화 않는 이것보다 CompPoint에 더있다가)

그런 다음,이 테스트는 실패

[TestMethod()] 
    public void compPointTest() { 
     Assert.AreEqual(new CompPoint(0, 0), new CompPoint(0, 0)); 
    } 

무엇 오전 내가 오해 한단 말이야? 참조 용평을 사용하는 Assert.AreEqual()입니까? 내 Equals() 기능이 CompPoint에 엉망이 되었습니까?

가 이 기능은 또한 실패

:

public void EqualsTest() { 
     Assert.IsTrue(new CompPoint(1, 1).Equals(new CompPoint(1, 1))); 
    } 

이에 대한이 이유는 것 나는 Dictionary을 사용하고, 그것이 내가 희망을 줄 방법을 작동하지 않는 것입니다 :

[TestMethod()] 
    public void dictCompPointTest() { 
     IDictionary<CompPoint, int> dict = new Dictionary<CompPoint, int>(); 
     dict[new CompPoint(0, 0)] = 4; 
     dict[new CompPoint(0, 0)] = 24; 
     dict[new CompPoint(0, 0)] = 31; 

     Assert.AreEqual(31, dict[new CompPoint(0, 0)]); 
     Assert.AreEqual(1, dict.Count); 
    } 

이 메시지와 함께 테스트가 실패합니다.

테스트 방법 ShipAILabTest.BoardUtilsTest.dictCompPointTest 던져 예외 : System.Collections.Generic.KeyNotFoundException : 주어진 키가 사전에 없습니다.

이 테스트는 나의 기대를 캡슐화합니다. 키가 매번 동일하기 때문에 값을 덮어 쓰길 바라고 있습니다. 평등성을 테스트하기 위해 사용하는 Dictionary은 무엇입니까?

UPDATE

: 나는 토마스의 제안에 따라, 동등의 기능을 추가, 지금은 CompPoint 비교 테스트가 작동하고 dictCompPointTest 작품. 키가 new CompPoint(0, 1)을 때 키가 new CompPoint(4, 1)을 때

[TestMethod()] 
    public void dictCPTest2() { 
     IDictionary<CompPoint, int> dict = new Dictionary<CompPoint, int>(); 
     dict[new CompPoint(2, 2)] = 2; 
     dict[new CompPoint(2, 2)] = 2; 

     Assert.AreEqual(1, dict.Count); 
    } 

테스트는 실패가 아니라 :

public override bool Equals(Object o) { 
     if (!(o is CompPoint)) { 
      throw new ArgumentException(String.Format("argument is not a CompPoint (%s given)", o)); 
     } 
     CompPoint cp = (CompPoint)o; 

     return this.X == cp.X && this.Y == cp.Y; 
    } 

불가사의,이 테스트는 계속 실패. 왜 이것이 다른 가치가 아닌 일부 가치에 작용할 수 있습니까?

더 많은 수수께끼 : 해시 코드 기능이 제대로 작동하지 않는 것 같습니다. 이 테스트는 실패합니다.

[TestMethod()] 
    public void hashCodeTest() { 
       int x = 0; 
       int y = 0; 
       Assert.AreEqual(new CompPoint(x, y).GetHashCode(), new CompPoint(x, y).GetHashCode());  
    } 

해시 코드 기능은 위에 나와 있습니다. 여기에 어떤 문제가 있습니까? 두 개의 CompPoint 객체가 동일한 해시 코드를 가져야하지 않습니까? 어쩌면 base.getHashCode()에 대한 내 전화가 문제입니까?

답변

1

Equals을 재정의하는 경우 GetHashCode을 재정의해야합니다. 사전에서 첫 번째 인스턴스에서 두 개의 키가 일치하는지 확인합니다. (GetHashCode에서 동일한 값을 돌려 동일한 것으로 간주되는 동일한 타입의 임의의 두 개체.)

public class CompPoint : IEquatable<CompPoint> 
{ 
    // ... 

    public override bool Equals(object obj) // object 
    { 
     return this.Equals(obj as ComPoint); 
    } 

    public bool Equals(CompPoint other) // IEquatable<ComPoint> 
    { 
     return !object.ReferenceEquals(other, null) 
      && this.X.Equals(other.X) 
      && this.Y.Equals(other.Y); 
    } 

    public override int GetHashCode() // object 
    { 
     int hash = 5419; 
     hash = (hash * 73) + this.X.GetHashCode(); 
     hash = (hash * 73) + this.Y.GetHashCode(); 
     return hash; 
    } 
} 
+0

이것은 흥미롭지 만 궁극적으로는 결실입니다. '사전'은 여전히 ​​중복을 감지하지 못합니다. –

+0

'getHashCode()'가 문제의 원인 일 수 있다고 생각합니다. (위 참조) –

+1

이 문제를 해결했는지 모르겠지만 GetHashCode 메서드가 여전히 위의 코드에 게시 한 것이면 여전히 두 인스턴스에 다른 코드가 생성됩니다 (즉, 두 개의 새로운 CompPoint (0, 0)) base.GetHashCode() – jeffora

3

Assert.AreEqualIEquatable<T>.Equals이 아닌 Object.Equals만을 사용한다고 생각합니다. 따라서 IEquatable<T>.Equals의 논리를 반영하려면 Equals을 재정의해야합니다.

또는 당신은 또한 Assert.IsTrue 사용할 수 있습니다 인터페이스가

명시 적으로 구현되기 때문에이 그것을, IEquatable<CompPoint>.EqualsObject.Equals보다는라고 수 있도록 : 나는 IEquatable<CompPoint>으로 P1과 P2를 선언

IEquatable<CompPoint> p1 = new CompPoint(0, 0); 
IEquatable<CompPoint> p2 = new CompPoint(0, 0); 
Assert.IsTrue(p1.Equals(p2)); 

주 편집 : 그건 그렇고, 당신은 CompPoint 클래스보다는 구조체로 선언 할 수도 있습니다. 이렇게하면 필드 값에 따라 값 유형이 비교되므로 아무 것도 구현할 필요가 없습니다.

+0

+1. 나를 때리십시오. 대신 'Equals()'논리를 복제하는 대신 다른 방법을 호출하십시오. –

+0

내 질문이 조금 업데이트되었습니다. 'CompPoint' 대신'IEquatable '을 타입으로 사용하는 것이 중요합니까? –

+0

'IEquatable '** ** 명시 적으로 ** 구현했기 때문에 중요합니다. 그러나 사전 키로 유형을 사용할 때 왜 작동하지 않는지 이해할 수 없습니다. S –

관련 문제