2012-03-14 7 views
9

Me parece que mi autocumplen Equals() y GetHashCode() con frecuencia para implementar la semántica de que los objetos comerciales con los mismos valores de propiedad son iguales. Esto lleva a que el código sea repetitivo de escribir y frágil de mantener (la propiedad se agrega y una o ambas anulaciones no se actualizan).Simplificar anulando Equals(), GetHashCode() en C# para una mejor capacidad de mantenimiento

El código termina buscando algo como esto (los comentarios sobre la aplicación son bienvenidos):

public override bool Equals(object obj) 
{ 
    if (object.ReferenceEquals(this, obj)) return true; 

    MyDerived other = obj as MyDerived; 

    if (other == null) return false; 

    bool baseEquals = base.Equals((MyBase)other); 
    return (baseEquals && 
     this.MyIntProp == other.MyIntProp && 
     this.MyStringProp == other.MyStringProp && 
     this.MyCollectionProp.IsEquivalentTo(other.MyCollectionProp) && // See http://stackoverflow.com/a/9658866/141172 
     this.MyContainedClass.Equals(other.MyContainedClass)); 
} 

public override int GetHashCode() 
{ 
    int hashOfMyCollectionProp = 0; 
    // http://computinglife.wordpress.com/2008/11/20/why-do-hash-functions-use-prime-numbers/ 
    // BUT... is it worth the extra math given that elem.GetHashCode() should be well-distributed? 
    int bitSpreader = 31; 
    foreach (var elem in MyCollectionProp) 
    { 
     hashOfMyCollectionProp = spreader * elem.GetHashCode(); 
     bitSpreader *= 31; 
    } 
    return base.GetHashCode()^//^is a good combiner IF the combined values are well distributed 
     MyIntProp.GetHashCode()^
     (MyStringProp == null ? 0 : MyStringProp.GetHashValue())^
     (MyContainedClass == null ? 0 : MyContainedClass.GetHashValue())^
     hashOfMyCollectionProp; 
} 

Mis preguntas

  1. es el sonido patrón de implementación?
  2. ¿Es adecuado dado que los valores de componentes contribuyentes están bien distribuidos? ¿Necesito multiplicar por 31-a-la-N cuando se combinan elementos de colección dado que su hash está bien distribuido?
  3. Parece que este código podría abstraerse en código que utiliza la reflexión para determinar propiedades públicas, crea un árbol de expresiones que coincida con la solución codificada a mano y ejecuta el árbol de expresiones según sea necesario. ¿Ese enfoque parece razonable? ¿Hay alguna implementación existente en alguna parte?
+2

Por qué la downvote (más de un año después de la publicación)? La pregunta es muy legítima. Si hay algo mal con eso, por favor di qué. –

Respuesta

4

MSDN realidad no decir "no es igual a la sobrecarga y otros tipos de mutables". Solía ​​decir que, pero ahora se dice:

Cuando se define una clase o estructura, a decidir si tiene sentido para crear una definición personalizada de la igualdad de valor (o equivalencia) para tipo. Normalmente, implementa la igualdad de valor cuando se espera que los objetos del tipo se agreguen a una colección de algún tipo, o cuando su objetivo principal es almacenar un conjunto de campos o propiedades.

http://msdn.microsoft.com/en-us/library/dd183755.aspx

Aún así, hay complejidades que rodean estabilidad del código hash mientras que un objeto participa en una colección hash (Dictionary<T,U>, HashSet<T>, etc.).

decidí optar por lo mejor de ambos mundos, como se indica aquí:

https://stackoverflow.com/a/9752155/141172

1

puedo encontrar el auto primordial es igual a() y GetHashCode() con frecuencia

  • MSDN dice: no es igual a la sobrecarga y otros tipos de mutables

¿Es adecuado dado que los valores de los componentes contribuyentes están bien distribuidos?

  • Sí, pero bueno no siempre están bien distribuida. Considere las propiedades int. Se aconseja cambiar con algunos (pequeños) números primos.
+0

¿Dónde dice eso MSDN? Traté de buscar en Google el texto literalmente y solo encontré esta pregunta. –

+0

Además ... para tomar un ejemplo simple de donde veo la utilidad para anular Equals (pero quizás me falta algo), ¿cómo implementaría una prueba unitaria que no anula Igual dadas 'MyDerived expected = new MyDerived() {/* Inicialización * /}; MyDerived actual = DoSomeTest(); Assert.AreEqual (esperado, real) '? –

+0

Y con respecto a^... en mi caso, cada valor de XORed es un resultado de GetHashCode(), que debe ser razonablemente distribuido. Según se implementó, ¿ves defectos en cómo uso ^? ¿Multiplicaría los elementos de la colección por un primo incluso si el hash de cada elemento de colección es el resultado de GetHashCode()? –

0

Tal vez estoy confundido aquí, pero no hay que el cheque en null devolver un 1 en lugar de un 0 en la anulación GetHashCode?

Así

MyStringProp == null ? 0 : MyStringProp.GetHashValue() 

debería ser

MyStringProp == null ? 1 : MyStringProp.GetHashValue() 
Cuestiones relacionadas