¿Cómo debo ir sobre la implementación de Object.GetHashCode () por la igualdad compleja?

StackOverflow https://stackoverflow.com/questions/1072058

Pregunta

Básicamente, Tengo el siguiente hasta el momento:

class Foo {
    public override bool Equals(object obj)
    {
        Foo d = obj as Foo ;
        if (d == null)
            return false;

        return this.Equals(d);
    }

    #region IEquatable<Foo> Members

    public bool Equals(Foo other)
    {
        if (this.Guid != String.Empty && this.Guid == other.Guid)
            return true;
        else if (this.Guid != String.Empty || other.Guid != String.Empty)
            return false;

        if (this.Title == other.Title &&
            this.PublishDate == other.PublishDate &&
            this.Description == other.Description)
            return true;

        return false;
    }
}

Por lo tanto, el problema es el siguiente: Tengo un campo no requiere Guid, que es un identificador único. Si esto no está establecido, entonces necesito para tratar de determinar la igualdad basada en métricas menos precisos como un intento de determinar si dos objetos son iguales. Esto funciona bien, pero hacen GetHashCode() desordenado ... ¿Cómo debería hacerlo? Una implementación ingenua sería algo como:

public override int GetHashCode() {
    if (this.Guid != String.Empty)
        return this.Guid.GetHashCode();

    int hash = 37;
    hash = hash * 23 + this.Title.GetHashCode();
    hash = hash * 23 + this.PublishDate.GetHashCode();
    hash = hash * 23 + this.Description.GetHashCode();
    return hash;
}

Pero ¿cuáles son las posibilidades de que los dos tipos de hash de la colisión? Desde luego, yo no esperaría que sea 1 in 2 ** 32. ¿Es esta una mala idea, y si es así, qué debería hacer eso?

¿Fue útil?

Solución

No creo que hay un problema con el enfoque que ha elegido para su uso. Preocuparse 'demasiado' sobre colisiones hash es casi siempre una indicación de sobre-pensar el problema; siempre y cuando el hash es altamente probable que sea diferente que debe estar bien.

En última instancia puede que incluso desee considerar dejando de lado la Description de su hash de todos modos si es razonable esperar que la mayoría de los objetos de tiempo se pueden distinguir en función de su título y fecha de publicación (libros?).

Incluso se puede considerar sin tener en cuenta el GUID en su función hash por completo, y sólo lo uso en el Equals aplicación para eliminar la ambigüedad del improbable (?) Caso de choques de patata.

Otros consejos

Un método muy fácil código hash para clases personalizadas es XOR bit a bit cada una de las códigos hash Fields juntos. Puede ser tan simple como esto:

int hash = 0;
hash ^= this.Title.GetHashCode();
hash ^= this.PublishDate.GetHashCode();
hash ^= this.Description.GetHashCode();
return hash;

Desde el anterior :

  

XOR tiene las siguientes propiedades agradables:

     
      
  • No dependen de fin de cómputo.
  •   
  • no bits “de desecho”. Si cambia ni un poco en uno de los componentes, el valor final va a cambiar.
  •   
  • Es rápido, en un solo ciclo, incluso la computadora más primitivo.
  •   
  • Conserva distribución uniforme. Si las dos piezas que se combinan están distribuidos de manera uniforme por lo que será la combinación. En otras palabras, no tiende a colapsar el rango del digerido en una banda más estrecha.
  •   

XOR no funciona bien si usted espera tener valores duplicados en sus campos como valores duplicados se anulan entre sí cuando XORed. Puesto que usted está hash juntos tres campos no relacionados que no debería ser un problema en este caso.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top