2009-09-14 11 views
7

De MSDNIComparable y equals()

Tipos que implementen IComparable debe invalidar Equals.Types que sobrescribir equals también tendrá prioridad sobre GetHashCode; de lo contrario, Hashtable podría no funcionar correctamente.

No lo entendí del todo. ¿Alguien puede explicarlo?

+0

Para obtener más información sobre la relación entre Equal y GetHashCode: http: // stackoverflow.com/questions/371328/why-is-it-important-to-override-gethashcode-when-equals-method-is-overriden-in-c –

+0

También tenga en cuenta que si bien es necesario que los contratos de IComparable, Equals y GetHashCode() se adhiere en todos los casos, no necesariamente se requiere implementar explícitamente los tres, siempre que se consigan resultados consistentes. Principalmente eso significa que dos objetos con el mismo código hash son iguales, y devuelve 0 en CompareTo(). – rushinge

+0

@rushinge Creo que la declaración es incorrecta: 'Principalmente eso significa que dos objetos con el mismo código hash son iguales, y devuelve 0 en CompareTo()'. . Si los objetos son iguales, se recomienda que GetHashCode() devuelva el mismo valor y CompareTo() para devolver 0. Puede producir fácilmente instancias diferentes/no iguales que devuelven el mismo código hash :) –

Respuesta

11

IComparable es una interfaz que define que dos instancias de la clase implementadora se pueden ver como superiores, inferiores o iguales entre sí. Como ha definido la igualdad en los métodos de esa interfaz, también debe anular el método Equals (y el operador de igualdad) para garantizar que los resultados de los dos sean coherentes.

public class EqualityTest : IComparable<EqualityTest> 
{ 
     public int Value { get; set; } 

     public int CompareTo(EqualityTest other) 
     { 
      return this.Value.CompareTo(other.Value); 
     } 
} 

En el ejemplo anterior he implementado IComparable, pero no se reemplaza Igual. Si llama a CompareTo con dos instancias separadas de la clase que tienen el mismo valor, dirá que hay iguales. Si llama a Equals con las mismas dos instancias, dirá que son y no igual que probará para ver si son el mismo objeto (la implementación predeterminada de Equals).

dos artículos iguales deben devolver el mismo código hash (que se utiliza para encontrar rápidamente los elementos utilizados como claves en las tablas hash) por lo que si se reemplaza es igual, entonces también deberían anular GetHashCode()


Como ejemplo que acabo de crear la siguiente clase en mi IDE:

public class EqualityTest 
{ 
    public string A { get; set; } 
    public string B { get; set; } 
} 

y corrió función útil "Generar igualdad" de ReSharper diciendo que quería tanto a como B para afectar a la igualdad. Este es el código que creó:

public bool Equals(EqualityTest other) 
    { 
     if (ReferenceEquals(null, other)) 
     { 
      return false; 
     } 

     if (ReferenceEquals(this, other)) 
     { 
      return true; 
     } 

     return Equals(other.A, A) && Equals(other.B, B); 
    } 

    public override bool Equals(object obj) 
    { 
     if (ReferenceEquals(null, obj)) 
     { 
      return false; 
     } 

     if (ReferenceEquals(this, obj)) 
     { 
      return true; 
     } 

     if (obj.GetType() != typeof(EqualityTest)) 
     { 
      return false; 
     } 

     return Equals((EqualityTest)obj); 
    } 

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

    public static bool operator ==(EqualityTest left, EqualityTest right) 
    { 
     return Equals(left, right); 
    } 

    public static bool operator !=(EqualityTest left, EqualityTest right) 
    { 
     return !Equals(left, right); 
    } 

Así que si está sustituyendo Igual entonces también debe definir todo lo anterior para garantizar la coherencia, si está implementando IComparable continuación, lo mismo se aplica.

+0

En mi opinión, si existe una posibilidad de que un tipo generalmente tenga un orden de clasificación claro, pero puede haber grupos de valores que no son equivalentes entre sí, pero que no tienen una clasificación natural relativa entre sí, sería completamente apropiado que 'CompareTo()' devuelva cero, pero para 'Equals()' para devolver falso (por ejemplo, yo postularía que 'Decimal' debería comportarse de esa manera al comparar' 1.0m' y '1.00m'). En mi opinión, 'igual' debería definir una relación de igualdad relativamente estricta, incluso en los casos en que' == 'o' CompareTo' podría definir uno más flexible. – supercat

0

Hay dos formas de que los objetos en el código podrían ser comparados: Equals y GetHashCode

Para su objeto a comparar adecuadamente en todas las situaciones, cuando se anula el Equals método (utilizado para algunas comparaciones), debe también anula GetHashCode (usado en el resto).

Si invalida una pero no la otra, según su código, podría obtener resultados inesperados.

1

IComparable se utiliza para comparar dos objetos. Si se consideran iguales, Compare devolverá 0. Sería muy inesperado si IComparable.Compare devolviera cero para dos objetos, pero obj1.Equals (obj2) devolvió el valor falso, ya que esto implica dos significados diferentes de igualdad para los objetos.

Cuando una clase anula Equals, también debe anular GetHashCode, ya que dos objetos iguales deben hash con el mismo valor, y este hash debe basarse en los campos/propiedades utilizados en la implementación de igualdad.

+0

Si IComparable.Compare devuelve cero, ¿eso significa realmente que los artículos deben considerarse iguales, o simplemente que no existe una relación clara ordenada? Supongamos que uno tiene una clase inmutable ScheduleEvent que incluye los campos EventTime de tipo DateTime y EventAction de tipo MethodInvoker. Los objetos ScheduleEvent tendrían un orden natural basado en EventTime, pero afirmaría que los objetos ScheduleEvent con el mismo EventTime pero diferentes delegados deberían devolver 0 desde CompareTo, pero False desde Equals. Eso parecería más limpio que cualquier otro comportamiento. – supercat