c# gethashcode

gethashcode c# override



implementar GetHashCode() para objetos que contienen colecciones (4)

Como guía, el hash de un objeto debe ser el mismo durante toda la vida útil del objeto. Dejaría la función GetHashCode sola y no la sobrescribiría. El código hash solo se usa si desea colocar sus objetos en una tabla hash.

Debería leer el excelente artículo de Eric Lippert sobre códigos hash en .NET: Pautas y reglas para GetHashCode .

Citado de ese artículo:

Pauta: el entero devuelto por GetHashCode nunca debe cambiar

Regla: el entero devuelto por GetHashCode nunca debe cambiar mientras el objeto esté contenido en una estructura de datos que dependa de que el código hash permanezca estable

Si el código hash de un objeto puede mutar mientras está en la tabla hash, entonces claramente el método Contains deja de funcionar. Coloca el objeto en el cubo # 5, lo muta, y cuando pregunta al conjunto si contiene el objeto mutado, lo busca en el cubo # 74 y no lo encuentra.

La función GetHashCode que implementó no devolverá el mismo código hash durante la vida útil del objeto. Si usa esta función, se encontrará con problemas si agrega esos objetos a una tabla hash: el método Contains no funcionará .

Considera los siguientes objetos:

class Route { public int Origin { get; set; } public int Destination { get; set; } }

Ruta implementa operadores de igualdad.

class Routing { public List<Route> Paths { get; set; } }

Usé el siguiente código para implementar el método GetHashCode para el objeto de enrutamiento y parece funcionar, pero me pregunto si esa es la forma correcta de hacerlo. Confío en los controles de igualdad y, como no estoy seguro, pensé en preguntarles, chicos. ¿Puedo simplemente sumar los códigos hash o necesito hacer más magia para garantizar el efecto deseado?

public override int GetHashCode() => { return (Paths != null ? (Paths.Select(p => p.GetHashCode()) .Sum()) : 0); }

GetHashCode() varias preguntas de GetHashCode() aquí, así como también el artículo de MSDN y Eric Lippert sobre este tema, pero no pude encontrar lo que buscaba.


Creo que tu solución está bien. (Observación posterior: el método de Sum de LINQ actuará en un contexto checked , por lo que puede obtener una OverflowException muy fácilmente, lo que significa que no está tan bien, después de todo). Pero es más habitual hacer XOR (adición sin acarreo). Entonces podría ser algo como

public override int GetHashCode() { int hc = 0; if (Paths != null) foreach (var p in Paths) hc ^= p.GetHashCode(); return hc; }

Anexo (después de que la respuesta fue aceptada):

Recuerde que si alguna vez usa este tipo de Routing en un Dictionary<Routing, Whatever> , un HashSet<Routing> u otra situación en la que se usa una tabla hash, su instancia se perderá si alguien altera (muta) el Routing después de que haya Se ha añadido a la colección.

Si está seguro de que eso nunca sucederá, use mi código de arriba. Dictionary<,> y así sucesivamente seguirá funcionando si se asegura de que nadie altera el Routing que se hace referencia.

Otra opción es simplemente escribir.

public override int GetHashCode() { return 0; }

Si crees que el código hash nunca será usado. Si cada instancia devuelve 0 para el código hash, obtendrá un rendimiento muy malo con las tablas hash, pero su objeto no se perderá. Una tercera opción es lanzar una NotSupportedException .


El código de la respuesta de Jeppe Stig Nielsen funciona, pero podría llevar a que se repitan muchos valores de código hash. Digamos que está haciendo un hash de una lista de entradas en el rango de 0-100, entonces su código de hash estará garantizado entre 0 y 255. Esto genera muchas colisiones cuando se usa en un Diccionario. Aquí hay una versión mejorada:

public override int GetHashCode() { int hc = 0; if (Paths != null) foreach (var p in Paths) { hc ^= p.GetHashCode(); hc = (hc << 7) | (hc >> (32 - 7)); //rotale hc to the left to swipe over all bits } return hc; }

Este código involucrará al menos todos los bits a lo largo del tiempo a medida que más y más elementos se hayan introducido.


No creo que sea una forma correcta de hacerlo, ya que para determinar el código hash final, tiene que ser único para el objeto especificado. En su caso, haga un Sum() , que puede producir el mismo resultado con diferentes hashcodes en la colección (al final, los hashcodes son solo números enteros).

Si su intención es determinar la igualdad en función del contenido de la colección, en este punto solo compare estas secciones entre dos objetos. Podría ser una operación lenta, por cierto.