2010-07-23 23 views
13

Hola a todos, he estado leyendo sobre la mejor manera de poner en práctica la anulación GetHashCode() para objetos en .NET, y la mayoría de las respuestas que implican correr a través de los números de alguna manera munging conjunto de los miembros que están tipos numéricos para encontrar un método. El problema es que tengo un objeto que usa una cadena alfanumérica como clave, y me pregunto si hay algo fundamentalmente erróneo con solo usar una identificación interna para objetos con cadenas como claves, algo como lo siguiente?GetHashCode() con claves de cadena


// Override GetHashCode() to return a permanent, unique identifier for 
// this object. 
static private int m_next_hash_id = 1; 
private int m_hash_code = 0; 
public override int GetHashCode() { 
    if (this.m_hash_code == 0) 
    this.m_hash_code = <type>.m_next_hash_id++; 
    return this.m_hash_code; 
} 

¿Hay una mejor manera de llegar a un código hash único para un objeto que utiliza una cadena alfanumérica como su clave? (Y no, las partes numéricas de la cadena alfanumérica no son únicas, algunas de estas cadenas en realidad no tienen números en absoluto). ¡Cualquier pensamiento sería apreciado!

Respuesta

19

Puede llamar GetHashCode() en los valores no numéricos que se utilizan en su objeto.

private string m_foo; 
public override int GetHashCode() 
{ 
    return m_foo.GetHashCode(); 
} 
+0

¿Pero y si esa cadena cambia? Por ejemplo, podría crear un nuevo objeto Usuario con: Usuario foo = nuevo Usuario(); y el constructor establece User.Id = "". Más tarde, si digo User.Id = "A12345"; y devuelvo this.Id.GetHashCode() como resultado de foo.GetHashCode(), ¿no habrá cambiado, violando el principio de que el código hash de un objeto nunca debería cambiar? –

+6

El objeto ha cambiado. El código hash * tiene que cambiar también *. –

+0

@King - hay un par de formas diferentes de usar los códigos hash. El valor del código hash debe ser siempre el mismo dado el mismo valor inicial. Si su valor es mutable, necesita almacenar el código hash resultante y devolverlo en su lugar cuando se invoca 'GetHashCode()'. –

0

Sí, una forma mejor sería usar el código hash de la cadena que ya tiene. Si la cadena alfanumérica define la identidad del objeto que tienes, su hashcode funcionará muy bien para el código hash de tu objeto.

La idea de incrementar un campo estático y que sirva como el código hash, es una mala. El código hash debe tener una distribución uniforme en el espacio de valores posibles. Esto asegura, entre otras cosas, que funcionará bien cuando se utiliza como clave en una tabla hash.

0

Creo que en general quiere GetHashCode() devolver algo que identifica al objeto por su valor, en lugar de lo que es ejemplo, si yo estoy entendiendo la idea aquí, creo que su método podría garantizar GetHashCode() en dos objetos diferentes con valores equivalentes haría devuelve hashes diferentes solo porque son instancias diferentes.

GetHashCode() está destinado a devolver un valor que le permite comparar dos valores de objetos, no sus referencias.

2

Los códigos hash no tienen que ser exclusivos. Siempre que su implementación Equals sea correcta, puede devolver el mismo código hash para dos instancias. La lógica m_next_hash_id está rota, ya que permite que dos objetos tengan diferentes códigos hash incluso si comparan iguales.

MSDN ofrece un buen conjunto de instrucciones sobre cómo implementar Equals y GetHashCode. Several of the examples here implementar GetHashCode en términos de los códigos hash de los campos de un objeto

18

Este no es un buen patrón para generar hashes para un objeto.

Es importante undunderstand el propósito de GetHashCode() - es una forma de generar una representación numérica de las propiedades de identidad de un objeto. Los códigos Hash se utilizan para permitir que un objeto sirva como clave en un diccionario y, en algunos casos, para acelerar las comparaciones entre tipos complejos.

Si simplemente genera un valor aleatorio y lo llaman un código hash, no tiene capacidad de repetición. Otra instancia con los mismos campos clave tendrá un código hash diferente y violará el comportamiento esperado por las clases como HashSet, Dictionary, etc.

Si ya tiene un miembro de cadena de identificación en su objeto, simplemente devuelva su código hash .

El documentation on MSDN for implementers of GetHashCode() es una lectura obligada para cualquier persona que planea sobre la sustitución de ese método:

Notas para los implementadores

una función hash se utiliza para generar rápidamente un número (almohadilla código) que corresponde al valor de un objeto. Las funciones hash son generalmente específicas para cada tipo y, para unicidad, deben usar al menos uno de los campos de instancia como entrada.

una función hash debe tener las siguientes propiedades:

Si dos objetos comparan como iguales, el método GetHashCode para cada objeto debe devolver el mismo valor. Sin embargo, si dos objetos no se comparan como iguales, los métodos GetHashCode para el objeto dos no tienen que devolver valores diferentes.

El método GetHashCode para un objeto debe volver consistentemente el mismo código hash siempre y cuando no hay modificación del estado del objeto que determina el valor de retorno de del objeto es igual método. Tenga en cuenta que este es verdadero solo para la ejecución actual de una aplicación, y que se puede devolver un código hash diferente si la aplicación se ejecuta nuevamente.

Para obtener el mejor rendimiento, una función de hash debe generar una distribución aleatoria para todas las entradas.

Por ejemplo, la puesta en práctica del método GetHashCode proporcionada por la clase cadena devuelve hash de idéntica códigos de valores de cadenas idénticas. Por lo tanto, dos objetos String devuelven el mismo código hash si representan el mismo valor de cadena. Además, el método utiliza todos los caracteres en la cadena para generar una salida razonable al azar distribuida, incluso cuando la entrada se centra en ciertas gamas (por ejemplo, muchos usuarios podrían tener cadenas que contienen sólo el menor 128 ASCII caracteres, aunque una cadena puede contener cualquiera de los 65.535 caracteres Unicode).

Cuestiones relacionadas