2009-09-10 11 views
12

He usado Dictionary (TKey, TValue) para muchos propósitos. Pero no he encontrado ningún escenario para implementar GetHashCode() que creo que se debe a que mis claves eran de tipos primarios como int y string. Tengo curiosidad por saber los escenarios (ejemplos del mundo real) cuando uno debe usar un objeto personalizado para clave y así implementar métodos GetHashCode() Igual() etc.¿Cuándo hacemos GetHashCode() para un diccionario?

Y, ¿es necesario implementar un objeto personalizado para la clave? funciones?

+0

posible duplicado de [¿Por qué es importante anular GetHashCode cuando se invalida el método Equals?] (Http://stackoverflow.com/questions/371328/why-is-it-important-to-override-gethashcode-when- equals-method-is-overridden) – nawfal

Respuesta

13

Debe anular Equals y GetHashCode siempre que el valor predeterminado Object.Equals (pruebas de igualdad de referencia) no sea suficiente. Esto sucede, por ejemplo, cuando el tipo de clave es un tipo personalizado y desea que dos claves se consideren iguales incluso en los casos en que no son la misma instancia del tipo personalizado.

Por ejemplo, si la clave es tan simple como

class Point { 
    public int X { get; set; } 
    public int Y { get; set; } 
} 

y quiere dos Point s dos se consideran iguales si sus X s son iguales y sus Y s son iguales, entonces necesitará para anular Equals y GetHashCode.

+0

con respecto a un Dictionary , ¿qué deben ser iguales y GetHashCode si 1) edito el objeto en su sitio y cambio 'point.X' por' point.Y'? ¿Se debe eliminar el valor y volver a agregarlo al diccionario? – LamonteCristo

2

Un ejemplo es cuando necesita crear una clave compuesta (es decir, una clave compuesta de más de un dato). Esa clave compuesta sería un tipo personalizado que tendría que anular esos métodos.

Por ejemplo, supongamos que tiene un caché en la memoria de registros de direcciones y desea verificar si hay una dirección en el caché para guardar un viaje costoso a la base de datos para recuperarlo. Digamos también que las direcciones son únicas en términos de sus calles , 1 y , código postal campos. Se podría implementar su caché con algo como esto:

class AddressCacheKey 
{ 
    public String StreetOne { get; set; } 
    public String ZipCode { get; set; } 

    // overrides for Equals and GetHashCode 
} 

y

static Dictionary<AddressCacheKey,Address> cache; 

Desde su tipo AddressCacheKey anula los métodos Equals y GetHashCode que sería un buen candidato para una llave en el diccionario y que le ser capaz de determinar si era necesario realizar un viaje a la base de datos para recuperar un registro basado en más de un dato.

1

Tiene dos preguntas aquí.

  1. cuándo se necesita para implementar GetHashCode()
  2. ¿Alguna vez utilizar un objeto para una clave de diccionario.

Comencemos por 1. Si está escribiendo una clase que posiblemente pueda ser utilizada por otra persona, querrá definir GetHashCode() e Igual(), cuando la referencia Equals() no sea suficiente. Si no está planeando usarlo en un diccionario, y es para su propio uso, entonces no veo razón para omitir GetHashCode() etc.

Para 2), debe usar un objeto cada vez que lo necesite tener una búsqueda de tiempo constante desde un objeto a otro tipo. Dado que GetHashCode() devuelve un valor numérico y colecciones almacena referencias, no hay penalización por usar un Objeto sobre un Int o una cadena (recuerde que una cadena es un objeto).

9

Sólo para que quede claro: Hay una cosa importante sobre Dictionary<TKey, TValue> y GetHashCode(): Diccionario utiliza GetHashCode para determinar si dos claves son iguales, es decir, si <TKey> es de tipo personalizado que debe preocuparse por la implementación de GetHashCode() cuidadosamente. Como Andrew Hare señaló, esto es fácil, si tiene un tipo simple que identifique su objeto personalizado sin ambigüedades. En caso de que tenga un identificador combinado, se vuelve un poco más complicado.

Como ejemplo, considere un número complejo como TKey. Un número complejo está determinado por su real y su parte imaginaria. Ambos son de tipo simple, p. double. Pero, ¿cómo identificarías si dos números complejos son iguales? Implementa GetHashode() para su tipo complejo personalizado y combina ambas partes de identificación.

Encontrará más información sobre esta última here.

ACTUALIZACIÓN

Basado en el comentario de Ergwun he comprobado el comportamiento de Dictionary<TKey, TValue>.Add con especial respeto a TKey 's ejecución de Equals(object) y GetHashCode(). I debo confesar que estaba bastante sorprendido por los resultados.

Dados dos objetos k1 y k2 de tipo TKey, dos objetos arbitrarios v1 y v2 de tipo TValue, y un diccionario vacío d de tipo Dictionary<TKey, TValue>, esto es lo que sucede cuando se añade v1 con llave k1 a d primero y v2 con llave k2 segundos (dependiendo de la implementación de TKey.Equals(object) y TKey.GetHashCode()):

k1.Equals(k2) k1.GetHashCode() == k2.GetHashCode() d.Add(k2, v2) 
false   false         ok 
false   true         ok 
true   false         ok 
true   true         System.ArgumentException 

Con clusion: estaba equivocado ya que originalmente pensé que el segundo caso (donde Equals devuelve false pero ambos objetos clave tienen el mismo código hash) elevaría un ArgumentException. Pero como el tercer caso muestra el diccionario de alguna manera, usa GetHashCode(). De todos modos, parece ser un buen consejo que dos objetos que son del mismo tipo y son iguales deben devolver el mismo código hash para garantizar que las instancias Dictionary<TKey, TValue> funcionen correctamente.

+9

-1 El diccionario NO utiliza 'GetHashCode()' para determinar si dos claves son iguales. Es decir, un diccionario puede contener entradas separadas cuyas claves tienen el mismo código hash. El diccionario puede ser menos eficiente, pero seguirá funcionando. – Ergwun

+2

+1 Para la actualización :) – Ergwun

+0

Sí, debe asegurarse de que los objetos que son iguales devuelven el mismo código hash (consulte http://msdn.microsoft.com/en-us/library/ms182358.aspx). – Ergwun

Cuestiones relacionadas