2010-12-07 11 views
9

Tengo algunos objetos con un montón de campos y me veo en la necesidad de implementar GetHashCode e Igual. Es doloroso que ir aunque cada campo de forma manual por lo que les escribió así:¿Por qué no debería implementar Equals y GetHashCode usando reflection?

public override int GetHashCode() 
{ 
    int hash = 17; 
    foreach (PropertyInfo p in GetType().GetProperties()) 
    { 
     hash = hash * 23 + p.GetValue(this, null).GetHashCode(); 
    } 
    return hash; 
} 

public override bool Equals(object obj) 
{ 
    foreach (PropertyInfo p in GetType().GetProperties()) 
    { 
     if (p.GetValue(obj, null) != p.GetValue(this, null)) 
      return false; 
    } 
    return true; 
} 

Aparte de consideraciones de velocidad Por qué no debería ponerlas en práctica como ésta?

+0

Aparte de los problemas de velocidad, tenga en cuenta que no todos las implementaciones correctas de 'GetHashCode' y' Equals' son equivalentes al algoritmo anterior. Por cierto, hay varios problemas con el código publicado. Puede eliminar la referencia 'null' en varios lugares. Además, su versión de 'Equals' utiliza la igualdad de referencia entre las propiedades correspondientes, que no es la expresión más común. – Ani

+0

Es curioso que lo preguntes, lo es. – stimms

+0

Use ReSharper: generará las implementaciones correctas de 'Equals' y' GetHashCode' por usted. –

Respuesta

7

Estas son algunas de las razones que evitaría esta ruta

  • Es mucho más fiable para comparar campos en lugar de las propiedades
  • Su código hace la suposición errónea de que dos objetos se consideran iguales si son la misma referencia (estás usando ==). Este no es el caso, ya que muchos tipos implementan la igualdad de valores a través del .Equals. Es muy posible y legal que se consideren dos referencias diferentes Equals y supere su prueba.
  • Si esta forma de Igualdad se utiliza de manera amplia a través de su base de código, muy fácilmente dará lugar a recursiones infinitas cuando el gráfico de objetos tenga ciclos.
  • El GetHashCode método ignora que una propiedad podría ser null

A continuación se muestra un ejemplo concreto de un tipo que podría causar una recursión infinita en su aplicación

class C1 { 
    public object Prop1 { get; set; } 
}; 

var local = new C1(); 
local.Prop1 = local; 
var x = local.GetHashCode(); // Infinite recursion 
+0

recursividad infinita es un muy buen punto – stimms

5

Cualquier valor de las propiedades será enmarcado por las llamadas GetValue, lo que significa que nunca se compararán igual aunque tengan el mismo valor.

Esto se puede evitar mediante una llamada al método estático Equals(x,y) - que luego se remiten al método virtual x.Equals(y) si es necesario - en lugar de utilizar la no virtual == operador, que siempre pondrá a prueba la igualdad referencia en este caso.

if (!object.Equals(p.GetValue(obj, null), p.GetValue(this, null))) 
    return false; 
+0

Typo corregido, pero! = Izquierda para mantener su respuesta válida – stimms

+0

'a.Equals (b)' arrojará si 'a' es' null'; 'Object.Equals (a, b)' devolverá 'false'. –

+0

@Tim: Buen punto. Actualizado. – LukeH

2
  1. Se puede dar un hash mal condicionado (no todas las propiedades son iguales en la determinación de la identidad del objeto.)

  2. Como actualmente implementado, el cálculo de hash puede rebosar.

2

Si su objeto es igual solamente si todas las propiedades son iguales y luego seguir adelante. Pero lo dudo. Por ejemplo, un empleado es único por su identificación de empleado. No podrá comparar los cambios en los datos de los empleados si hace esto.

Cuestiones relacionadas