How to implement IEqualityComparer on an immutable generic Pair structure?

I currently have this (edited after reading the tip):

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

The problem is that First and Second may not be reference types (VS actually warns me about this), but the code is still compiling. Should I throw them (first and second) on objects before comparing them, or is there a better way to do this?

Edit: Please note: I want this structure to support values ​​and reference types (in other words, class constraining is not a valid solution)

2: , , , . -, SRP , - . -, (T) null - .

+3
7

, IEquatable:

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);
    }
  }
}
+2

IEqualityComparer ( , ).

, - , GetHashcode ( ) .

+2

- , " ", - .

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". fore-, "object.ReferenceEquals", . , , . "" "_ first" "_second", object.ReferenceEquals? - ?

+1

, (T) (K) .

, , - - , -. , , , _first _second .

0

, SRP. , , , ? .

:

Equals , null - . Equals - Pair, GetHashCode, - - - . , Equals . , , . , , . , , . , SO .

0

- ? , .

0

I don't get compilation warnings about this, but I assume you are talking about == null comparison? It seems that the casting would make it all cleaner, yes.

PS. You really have to use a separate class for comparison. This class, which fills two roles (being a couple and comparing pairs), is ugly.

0
source

Source: https://habr.com/ru/post/1697379/


All Articles