Básicamente, tengo los siguientes hasta el momento:¿Cómo debo implementar Object.GetHashCode() para la igualdad compleja?
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 debo tratar de determinar la igualdad basada en métricas menos precisas como un intento de determinar si dos objetos son iguales. Esto funciona bien, pero hace GetHashCode()
desordenado ... ¿Cómo debo hacerlo? Una implementación ingenua sería algo así 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? Ciertamente, no esperaría que fuera 1 in 2 ** 32
. ¿Es esta una mala idea, y si es así, cómo debería hacerlo?
Es más importante que su algoritmo hash esté de acuerdo con su algoritmo de igualdad que la distribución sea uniforme. Recuerde, el propósito del hash es únicamente obtener una distribución decente en una tabla hash; siempre y cuando no estés masivamente inclinado a un cubo en particular, las probabilidades son buenas, estarás bien. Si está preocupado, elija un escenario razonable que el consumidor de su objeto pueda encontrar (por ejemplo, poniendo algunos cientos de ellos en un diccionario, si es razonable) y realice algunas pruebas de desempeño para ver si obtiene una calificación aceptable. resultados. –
Lo que más he visto en el uso real era ~ 200, pero el uso típico es <30, así que probablemente tengas razón. –
Diablos, con menos de 30 elementos, una búsqueda lineal en una lista vinculada es probablemente un rendimiento razonable. Puede devolver un código hash de cero siempre, tener 100% de posibilidades de colisión y obtener un rendimiento aceptable. El objetivo de tener una buena distribución de los códigos hash es hacer que el rendimiento sea escalable cuando el tamaño del diccionario aumenta. Puede tener una mala distribución y obtener buenos resultados si solo va a poner una pequeña cantidad de elementos en la tabla. –