2011-05-12 18 views
9

¿Deberíamos anular las propiedades Equals y GetHashCode al implementar una comparación de instancias de clase personalizada?Igual a GetHashCode al comparar objetos

En el siguiente código tengo una colección de clases. La clase A se compara con el ID, la clase B - por Code.

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 

namespace ConsoleApplication2 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<I> bars = new List<I>(); 
      bars.Add(new A() { Id = 1, Code = "one A" }); 
      bars.Add(new B() { Id = 1, Code = "one B" }); 
      bars.Add(new A() { Id = 1, Code = "one A+" }); 
      bars.Add(new B() { Id = 1, Code = "one B" }); // Code = "one B+" 

      var distictBars = bars.Distinct(); 

      foreach (var item in distictBars) 
      { 
       Debug.WriteLine(item.Code); 
      } 
     } 
    } 

    interface I 
    { 
     string Code { get; set; } 
    } 

    class A : I, IEquatable<A> 
    { 
     public int Id { get; set; } 
     public string Code { get; set; } 

     public bool Equals(A other) 
     { 
      // this is the ??? comparison 
      return this.Id == other.Id; 
      //return this.Code == other.Code; 
     } 

     public override bool Equals(object obj) 
     { 
      if (obj is A) 
       return this.Equals(obj as A); 
      else 
       return object.ReferenceEquals(this, obj); 
     } 

     public override int GetHashCode() 
     { 
      // this is the wanted comparison 
      return this.Id; 
     } 
    } 

    class B : I, IEquatable<B> 
    { 
     public int Id { get; set; } 
     public string Code { get; set; } 

     public bool Equals(B other) 
     { 
      // this is the ??? comparison 
      return this.Id == other.Id; 
     } 

     public override bool Equals(object obj) 
     { 
      if (obj is B) 
       return this.Equals(obj as B); 
      else 
       return object.ReferenceEquals(this, obj); 
     } 

     public override int GetHashCode() 
     { 
      // this is the wanted comparison 
      return this.Code.GetHashCode(); 
     } 
    } 
} 

La salida es:

one A 
one B 

en caso de que el comentado Code = "one B+" la salida es

one A 
one B 
one B+ 

Ahora me pregunto para qué debo anular el Equals en la clase B si parece que esto no tiene efecto en la comparación?

¿Es suficiente anotar GetHasCode() para ese tipo de comparaciones?

+0

posible duplicado de [¿He implementado Equals()/GetHashCode() correctamente?] (Http://stackoverflow.com/questions/5700099/have-i-implemented-equals-gethashcode-correctly) –

Respuesta

12

Esto es lo que necesita saber sobre la relación entre Equals y GetHashCode.

Hash códigos son utilizados por hashtables para encontrar rápidamente un "cubo" en el que se espera que exista un elemento. Si los elementos están en dos categorías diferentes, la suposición es que no pueden ser iguales.

El resultado de esto es que usted debe ver un código hash, a efectos de determinar la singularidad, como una rápida negativo cheque: es decir, si dos objetos tienen diferentes códigos hash, que son no la misma (independientemente de lo que devuelvan sus métodos Equals).

Si dos objetos tienen mismo código hash, residirán en el mismo contenedor de una tabla hash. Luego se llamarán sus métodos Equals para determinar la igualdad.

Entonces GetHashCodedebe devolver el mismo valor para dos objetos que desee que se consideren iguales.

4

Siempre tiene que anularlos junto con y con implementaciones compatibles. Un medio de coincidencia/falta de coincidencia de código hash (respectivamente) "posible igualdad" y "no igualdad". El código hash por sí solo no indica igualdad. Por lo tanto, después de que se encuentra una coincidencia con código hash (o se usa para crear grupos de valores), Equals aún se verifica para determinar una coincidencia.

Si los dos no están de acuerdo, es posible que nunca encuentre coincidencias.

3

El método Distinct utilizará el método GetHashCode para determinar la desigualdad entre los elementos, y el método Equals para determinar la igualdad.

Primero se hace una comparación rápida usando el código hash para determinar qué elementos definitivamente no son iguales, es decir, tienen diferentes códigos hash, luego se comparan los elementos que tienen el mismo código hash para determinar cuáles son realmente iguales.

En su implementación de la clase B tiene una implementación inconsistente del método GetHashCode y Equals, por lo que la comparación no funcionará correctamente. Sus dos objetos B tienen diferentes códigos hash, por lo que no se compararán entre sí. Dos elementos que se consideran iguales también deben devolver el mismo código hash.

Si una clase implementa la interfaz IEquatable<T>, se utilizará el método Equals(T), de lo contrario, se utiliza el método Equals(object).