Hvordan implementerer IEqualityComparer gjøre på en uforanderlig generisk Pair struct?

stemmer
3

Foreløpig har jeg dette (redigert etter å ha lest råd):

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

Problemet er at første og andre ikke kan være referansetyper (VS faktisk advarer meg om dette), men koden fortsatt kompilerer. Bør jeg kastet dem (første og andre) til objekter før jeg sammenligne dem, eller er det en bedre måte å gjøre dette?

Edit: Merk at jeg ønsker dette struct å støtte verdi og referansetyper (med andre ord, begrensende av klassen er ikke en gyldig løsning)

Rediger 2: Når det gjelder hva jeg prøver å oppnå, jeg vil at dette skal fungere i en ordbok. Dernest er SRP ikke viktig for meg akkurat nå, fordi det er egentlig ikke essensen av dette problemet - det kan alltid bli refactored senere. For det tredje, sammenligning til standard (T) vil ikke fungere i stedet for å sammenligne med null - prøv det.

Publisert på 23/09/2008 klokken 12:50
kilden bruker
På andre språk...                            


7 svar

stemmer
2

Det ser ut som du trenger IEquatable stedet:

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);
    }
  }
}
Svarte 23/09/2008 kl. 15:14
kilden bruker

stemmer
2

Din IEqualityComparer implementering bør være en annen klasse (og definitivt ikke en struct som du ønsker å gjenbruke referanse).

I tillegg bør du hashCode aldri bli lagret, som standard GetHashcode implementering for en struct (som du ikke overstyre) vil ta som medlem i betraktning.

Svarte 23/09/2008 kl. 12:56
kilden bruker

stemmer
1

Hvis du bruker hashcodes i å sammenligne metoder, bør du sjekke for "virkelig verdi" hvis hash-koder er samme.

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;

Men det er littlebit problem med å sammenligne "_first" og "_second" feltene. Som standard referansetypene bruker forgrunnen likestilling sammenligne "object.ReferenceEquals" metoden, bud de kan overstyre dem. Så den riktige løsningen avhenger av "hva skal gjøre" det din sammenligne metoden. Bør bruke "lik" metoden "_first" & "_second" felt, eller object.ReferenceEquals? Eller noe mer komplisert?

Svarte 23/09/2008 kl. 13:03
kilden bruker

stemmer
0

Jeg får ikke noen advarsel når kompilering om dette, men jeg antar du snakker om == null sammenligning? En støpt virker som det ville gjøre alt dette litt renere, ja.

PS. Du bør bruke en egen klasse for comparer. Denne klassen som fyller to funksjoner (som et par og sammenligning av par) er ren stygg.

Svarte 23/09/2008 kl. 13:01
kilden bruker

stemmer
0

Kan jeg foreslå bruk av Lambda uttrykk som en parameter? Dette vil tillate deg å spesifisere hvordan å sammenligne de interne generiske typer.

Svarte 23/09/2008 kl. 12:59
kilden bruker

stemmer
0

Først av alt denne koden bryter SRP prinsippet. Pair klassen brukes til å holde parene hvis elementer, ikke sant? Det er feil å delegere likestilling sammenligne funksjonalitet til den.

Neste la ta en titt på koden din:

Tilsvarer metoden vil mislykkes hvis et av argumentene er null - ikke bra. Tilsvarer bruker hash code of Pair klassen, men ta en titt på definisjonen av GetHashCode, det bare en kombinasjon av par medlemmer hash-koder - det er har ingenting å gjøre med likestilling av elementer. Jeg forventer at lik metoden vil sammenligne faktiske data. Jeg er for opptatt i øyeblikket for å gi korrekt gjennomføring, dessverre. Men fra første blikk, synes du kode for å være feil. Det ville være bedre hvis du gir oss beskrivelse av hva du ønsker å oppnå. Jeg er sikker på at SO medlemmer vil være i stand til å gi deg noen råd.

Svarte 23/09/2008 kl. 12:58
kilden bruker

stemmer
0

Når det gjelder varsling, kan du bruke standard (T) og standard (K) i stedet for null.

Jeg kan ikke se hva du prøver å oppnå, men du bør ikke bruke hashCode å sammenligne for likestilling - det er ingen garanti for at to forskjellige objekter ikke vil ha samme hashCode. Også selv om din struct er uforanderlig, medlemmene _first og _second ikke.

Svarte 23/09/2008 kl. 12:57
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more