불변의 일반 쌍 구조물에서 iequalitycomparer를 구현하려면 어떻게해야합니까?

StackOverflow https://stackoverflow.com/questions/120783

  •  02-07-2019
  •  | 
  •  

문제

현재 나는 이것을 가지고있다 (읽기 조언 후 편집) :

struct Pair<T, K> : IEqualityComparer<Pair<T, K>>
{
    readonly private T _first;
    readonly private K _second;

    public Pair(T first, K second)
    {
        _first = first;
        _second = second;

    }

    public T First { get { return _first; } }
    public K Second { get { return _second; } }

    #region IEqualityComparer<Pair<T,K>> Members

    public bool Equals(Pair<T, K> x, Pair<T, K> y)
    {
        return x.GetHashCode(x) == y.GetHashCode(y);
    }

    public int GetHashCode(Pair<T, K> obj)
    {
        int hashCode = obj.First == null ? 0 : obj._first.GetHashCode();

        hashCode ^= obj.Second == null ? 0 : obj._second.GetHashCode();

        return hashCode;
    }

    #endregion

    public override int GetHashCode()
    {
        return this.GetHashCode(this);
    }

    public override bool Equals(object obj)
    {
        return (obj != null) && 
    (obj is Pair<T, K>) && 
    this.Equals(this, (Pair<T, K>) obj);
    }
}

문제는 첫 번째와 두 번째가 참조 유형이 아닐 수도 있다는 것입니다 (실제로는 이것에 대해 경고합니다). 코드는 여전히 컴파일됩니다. 비교하기 전에 (첫 번째와 두 번째) 객체에 캐스트해야합니까, 아니면 더 좋은 방법이 있습니까?

편집 : i 원하다 값과 참조 유형을 지원하기위한이 구조 (즉, 클래스에 의한 제약은 유효한 솔루션이 아닙니다)

편집 2 : 내가 달성하려는 것에 관해서는, 나는 이것이 사전에서 작동하기를 원합니다. 둘째, SRP는 지금 당장이 문제의 본질이 아니기 때문에 지금은 나에게 중요하지 않습니다. 나중에 항상 재현 할 수 있습니다. 셋째, 기본값 (t)과 비교하면 NULL과 비교하는 대신 작동하지 않습니다.

도움이 되었습니까?

해결책

대신 iquipatable이 필요한 것 같습니다.

internal struct Pair<T, K> : IEquatable<Pair<T, K>>
{
  private readonly T _first;
  private readonly K _second;

  public Pair(T first, K second)
  {
    _first = first;
    _second = second;
  }

  public T First
  {
    get { return _first; }
  }

  public K Second
  {
    get { return _second; }
  }

  public bool Equals(Pair<T, K> obj)
  {
    return Equals(obj._first, _first) && Equals(obj._second, _second);
  }

  public override bool Equals(object obj)
  {
    return obj is Pair<T, K> && Equals((Pair<T, K>) obj);
  }

  public override int GetHashCode()
  {
    unchecked
    {
      return (_first != null ? _first.GetHashCode() * 397 : 0) ^ (_second != null ? _second.GetHashCode() : 0);
    }
  }
}

다른 팁

iquealitycomparer 구현은 다른 클래스 여야합니다 (그리고 참조를 재사용하려는 구조물이 아닙니다).

또한, 구조물의 기본 gethashcode 구현 (재정의하지 않은)이 해당 멤버를 고려하기 때문에 해시 코드를 캐시해서는 안됩니다.

메소드 비교에서 해시 코드를 사용하는 경우 해시 코드가 동일하다면 "Realy Value"를 확인해야합니다.

bool result = ( x._hashCode == y._hashCode );
if ( result ) { result = ( x._first == y._first && x._second == y._second ); }
// OR?: if ( result ) { result = object.Equals( x._first, y._first ) && object.Equals( x._second, y._second ); }
// OR?: if ( result ) { result = object.ReferenceEquals( x._first, y._first ) && object.Equals( x._second, y._second ); }
return result;

그러나 "_first"와 "_second"필드를 비교하는 데는 거의 문제가 없습니다. 기본적으로 참조 유형은 "Object.ReferenceAls"메소드를 비교하는 Fore Equality를 사용합니다. 따라서 올바른 솔루션은 비교 방법의 "정확히 무엇을 해야하는지"에 따라 다릅니다. "_first"및 "_second"필드 또는 개체의 "Equals"방법을 사용해야합니까? 아니면 더 복잡한 것?

경고와 관련하여 NULL 대신 기본값 (t) 및 기본값 (k)을 사용할 수 있습니다.

당신이 달성하려는 것을 볼 수는 없지만 해시 코드를 사용하여 평등을 비교해서는 안됩니다. 두 개의 다른 객체에 동일한 해시 코드가 없다는 보장은 없습니다. 또한 당신의 구조물은 불변이지만 _first와 _second는 그렇지 않습니다.

우선이 코드는 SRP 원칙을 위반합니다. 쌍 클래스는 항목이라면 쌍을 잡는 데 사용됩니다. 기능을 비교하는 평등을 위임하는 것은 부정확합니다.

다음으로 코드를 살펴 보겠습니다.

인수 중 하나가 무인 상태 인 경우 동등한 방법이 실패합니다. Equals는 쌍 클래스의 해시 코드를 사용하지만 gethashcode의 정의를 살펴보십시오. 쌍 멤버 해시 코드의 조합 일뿐입니다. 항목의 평등과는 아무런 관련이 없습니다. Equals 방법이 실제 데이터를 비교할 것으로 기대합니다. 불행히도 올바른 구현을 제공하기에는 지금 너무 바빠요. 그러나 첫 번째 모습에서 코드는 잘못된 것 같습니다. 당신이 달성하고자하는 것에 대한 설명을 우리에게 제공한다면 더 나을 것입니다. 나는 회원들이 당신에게 약간의 조언을 줄 수있을 것이라고 확신합니다.

Lambda 표현식을 매개 변수로 사용하는 것을 제안 할 수 있습니까? 이를 통해 내부 일반 유형을 비교하는 방법을 지정할 수 있습니다.

이것에 대해 컴파일 할 때 경고를받지 못하지만 == null 비교에 대해 이야기하고 있다고 가정합니까? 캐스트는 이것을 다소 깨끗하게 만드는 것처럼 보입니다.

추신. 비교에 별도의 클래스를 사용해야합니다. 두 가지 역할을 채우는이 클래스 (쌍과 쌍을 비교)는 평범합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top