2010-06-09 17 views
8

Me dijeron que una de las muchas razones por las que las cadenas se volvían inmutables en la especificación C# era para evitar el problema de las HashTables que tenían claves cambiadas cuando las referencias a las claves cambiaban su contenido.C# Dictionary <> y teclas mutables

El tipo Diccionario <> permite utilizar tipos de referencia como clave. ¿Cómo evita el diccionario el problema de las claves alteradas que conducen a valores "extraviados"? ¿Hay un clon de miembro hecho de un objeto cuando se usa como clave?

Respuesta

9

El tipo Dictionary<TKey,TValue> no intenta proteger al usuario de la modificación de la clave utilizada. Es solo responsabilidad del desarrollador ser responsable de no mutar la clave.

Si piensa en esto un poco, esta es realmente la única ruta correcta que Dictionary<TKey,TValue> puede tomar. Considere la implicación de realizar una operación como un clon de miembro en el objeto. Para ser exhaustivo necesitarías hacer un clon profundo porque será posible que un objeto al que se hace referencia en la clave también se mute y, por lo tanto, afecte al código hash. Entonces, cada clave usada en la tabla tiene su gráfico de objeto completo clonado para protegerse contra la mutación. Esto sería a la vez con errores y posiblemente una operación muy costosa.

+1

Python, sin embargo, fue de otra manera y los datos mutables no están permitidos como una clave de caché. http://www.udacity.com/view#Course/cs212/CourseRev/apr2012/Unit/207010/Nugget/251006 –

5

La clase Dictionary<> no hace nada para protegerse contra un objeto clave mutable que se está modificando. Depende de usted saber si la clase que está utilizando como clave es mutable o no, y evitarla si es posible.

3

No evita esta situación. Es hasta el código de llamada para hacer cumplir este:

Mientras un objeto se utiliza como una clave en la Dictionary<TKey, TValue>, no debe cambiar en forma alguna que afecte a su valor hash. Cada clave en un Dictionary<TKey, TValue> debe ser única según el comparador de igualdad del diccionario. Una clave no puede ser null, pero un valor puede ser, si el tipo de valor TValue es un tipo de referencia.

(De MSDN)

8

Si está utilizando un tipo de referencia mutable como una clave, la implementación predeterminada de GetHashCode() garantizará la igualdad de hash independientemente del estado del objeto (es decir, el hash está ligada a la referencia, no el estado). Está en lo cierto, sin embargo, que un tipo mutable con semántica de igualdad de valores (donde GetHashCode presumiblemente depende del estado) es una mala elección para una clave de diccionario.

+0

Esta es una buena idea.Gracias por recordarme que GetHashCode para un objeto por defecto está basado en una instancia que creo que ahorra mucho tiempo a los desarrolladores. –

+0

Los tipos de clase mutable con semántica de igualdad de valores parecen una mala idea de todos modos. Si bien hay algunas excepciones (por ejemplo, 'double',' Decimal', 'List .Enumerator', etc.), la mayoría de los tipos en .net implementan' Equals (Object) 'para indicar la equivalencia; dado que los distintos elementos de clase mutables nunca son equivalentes, nunca deben informarse como 'iguales' (el comportamiento de 'List .Enumerator' deriva del hecho de que los tipos de valores en caja y sin caja tienen una semántica diferente, pero son necesarios para compartir el mismo método 'Igual'). – supercat

3

Si un tipo de referencia no anula Equals/GetHashCode, a un diccionario que use el comparador predeterminado no le importará ninguno de los campos o propiedades de los objetos clave, y por lo tanto no notará ni le importará si cambian. Es más simple pensar que el método GetHashCode predeterminado devuelve un número relacionado con un "ID de objeto", y el método Equals predeterminado como la comparación de "id de objeto". De hecho, en un sistema limitado a dos mil millones o menos de objetos, GetHashCode podría simplemente devolver una ID de objeto, pero por diversas razones también podría hacer otras cosas.

Si la única parte de un objeto que es examinado por Equals o GetHashCode es la ID del objeto, entonces para propósitos de esas funciones, todos los objetos son inmutables. Una vez que se crea un objeto, siempre tendrá el mismo ID, y ese ID nunca se usará para ningún otro objeto hasta que todos los rastros del ID del objeto anterior hayan desaparecido del universo.

Cuestiones relacionadas