2011-09-30 8 views
8

ho la seguente classeimplementazione IEquatables solo chiamato se la base Equals viene sovrascritto

class Product : IEquatable<Product> 
{ 
    public Guid Id { get; set; } 
    public bool Equals(Product other) 
    { 
     return Id.Equals(other.Id); 
    } 
} 

Se provo e creare un elenco unico degli elementi di una lista come segue

  Guid a = Guid.NewGuid(); 
     List<Product> listA = new List<Product>(); 
     listA.Add(new Product(){Id = a}); 

     List<Product> listB = new List<Product>(); 
     listB.Add(new Product() 
     { 
      Id = a 
     }); 
     Debug.Assert(listA.Union(listB).Count()==1); 

due articoli vengono restituiti, ciò si verifica fino a quando ho l'override del metodo Object.equalsQ, una volta che faccio questo e il mio codice è il seguente

class Product : IEquatable<Product> 
{ 
    public Guid Id { get; set; } 
    public bool Equals(Product other) 
    { 
     if (ReferenceEquals(null, other)) return false; 
     if (ReferenceEquals(this, other)) return true; 
     return other.Id.Equals(Id); 
    } 

    public override bool Equals(object obj) 
    { 
     if (ReferenceEquals(null, obj)) return false; 
     if (ReferenceEquals(this, obj)) return true; 
     if (obj.GetType() != typeof (Product)) return false; 
     return Equals((Product) obj); 
    } 

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

viene ora chiamato il metodo IEquatable Equals, ma solo se sovrascrivo il metodo base, inoltre, se metto un breakpoint sull'oggetto equals, il metodo non viene mai chiamato.

Perché è questo?

---- UPDATE

Quindi, con la classe del prodotto

class Product : IEquatable<Product> 
{ 
    public Guid Id 
    { 
     get; 
     set; 
    } 
    public bool Equals(Product other) 
    { 
     return Id.Equals(other.Id); 
    } 

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

} 

Se GetHashCode viene rimosso, l'attuazione IEquatable degli Eguali non è mai colpito Capisco si dovrebbe generalmente implementare Equals e GetHashCode insieme, è questo perché?

+1

Aggiungendo che l'implementazione di 'GetHashCode' alla tua classe originale ti dà il comportamento che vuoi, sembra. – AakashM

risposta

9

Il problema è nell'implementazione originale non si sta sovrascrivendo il metodo GetHashcode. Sotto il cofano, Union utilizza una struttura in stile Set<T> per rimuovere i duplicati. Questa struttura mette gli oggetti in bucket in base al valore restituito da GetHashCode. Se il codice hash doesnt't corrispondono tra oggetti uguali (che si deve fare) allora possono potenzialmente essere messi in diversi secchi e mai confrontati con Equals

In generale, se si implementa IEquatable<T> si dovrebbe sempre

  • Override Object.Equals
  • Override Object.GetHashCode

Non fare entrambe si terra in situazioni come questa.

nota, l'implementazione potrebbe essere semplificata un po

class Product : IEquatable<Product> 
{ 
    public Guid Id { get; set; } 
    public bool Equals(Product other) 
    { 
    if (ReferenceEquals(null, other)) { 
     return false; 
    } 
    return other.Id == this.Id; 
    } 

    public override bool Equals(object obj) 
    { 
    return Equals(obj as Product); 
    }  

    public override int GetHashCode() 
    { 
    return Id.GetHashCode(); 
    } 
} 
+0

È l'implementazione predefinita del resharper del metodo equals. Se questo è il caso, (e sono sicuro che tu sia corretto in BTW) perché il punto di interruzione non viene colpito? È un errore dell'utente? Anche il BOL qui http://msdn.microsoft.com/en-us/library/ms224763.aspx suggerisce che dovrebbe cercare IEquatable? –

+0

@KevHunter Ho aggiornato la mia risposta un po '. – JaredPar

+0

Sto usando il metodo LINQ Union standard, il codice sopra è da un'imbracatura di test per confermare quello che sto vedendo –

3

Documentazione per Enumerable.Union dice:

L'uguaglianza di default di confronto, di default, viene utilizzato per confrontare i valori di i tipi che implementano il Interfaccia IEqualityComparer (Of T) generica . Per confrontare un tipo di dati personalizzato, è necessario implementare questa interfaccia e fornire i propri metodi GetHashCode ed Equals per il tipo .

Stai implementando IEquatable. È necessario implementare IEqualityComparer.

Problemi correlati