2011-08-09 26 views
19

quiero usar un objeto personalizado como una clave de diccionario, sobre todo, tengo algo como esto: (No puedo usar .NET 4.0, así que no tengo tuplas)uso como objeto personalizado Diccionario Clave

class Tuple<A, B> : IEquatable<Tuple<A,B>> 
{ 
    public A AValue { get; set; } 
    public B BValue { get; set; } 

    public Tuple(A a, B b){ AValue = a; BValue = b; } 

    public bool Equals(Tuple<A, B> tuple) 
    { 
    return tuple.AValue.Equals(AValue) && tuple.BValue.Equals(BValue); 
    } 

    public bool Equals(object o) 
    { 
    return this.Equals(o as Tuple<A,B>); 
    } 
} 

Luego hago algo como esto.

var boolmap = new Dictionary<Tuple<bool, bool>, string>(); 
    boolmap.Add(new Tuple<bool,bool>(true, true), "A"); 
    boolmap.Add(new Tuple<bool,bool>(true, false), "B"); 
    boolmap.Add(new Tuple<bool,bool>(false, true), "C"); 
    boolmap.Add(new Tuple<bool,bool>(false, false), "D"); 
    var str = boolmap[new Tuple<bool,bool>(true, false)]; 

Aparece la excepción KeyNotFound en la última línea. Por qué es esto ? ¿No es suficiente que implemente IEquatable?

Gracias

+1

¿dónde está tu get hash code implementation? si pone un igual, siempre debe tener un código hash get – Manatherin

+7

Su código le da una advertencia, y por una razón. Cuando corrija esa advertencia, recibirá otra advertencia, y cuando corrija eso, su código funcionará. Nunca ignore las advertencias. –

+0

Podría haber visto: [using-an-object-as-a-generic-dictionary-key-in-net] (http: // stackoverflow.com/questions/634826/using-an-object-as-a-generic-dictionary-key-in-net) – nawfal

Respuesta

29

También es necesario para anular GetHashCode() (y preferiblemente también Equals()). Su objeto, que de lo contrario es igual, devuelve un código hash diferente, lo que significa que la clave no se encuentra cuando se busca.

El contrato GetHashCode() especifica que el valor de retorno de dos objetos DEBE ser igual cuando los dos objetos se consideran iguales. Esta es la raíz de tu problema; su clase no cumple con este requisito. El contrato no especifica que el valor debe ser diferente si no son iguales, pero esto mejorará el rendimiento. (Si todos los objetos devuelven el mismo código hash, es posible también utilizar una lista plana desde una perspectiva de rendimiento.)

Una aplicación simple en su caso podría ser:

public override int GetHashCode() 
{ 
    return AValue.GetHashCode()^BValue.GetHashCode(); 
} 

Nota que podría sea ​​una buena idea para probar si AValue o BValue son null. (Esto será algo complicado ya que no limiten los tipos genéricos A y B, por lo que no se puede simplemente comparar los valores de null -. Los tipos podría estar tipos de valor, por ejemplo)

también una buena idea para hacer clases que pretenda usar como claves del diccionario inmutables. Si cambia el valor de un objeto que se está utilizando como clave, el diccionario exhibirá un comportamiento extraño, ya que el objeto se encuentra ahora en un contenedor al que no pertenece.


Tenga en cuenta que usted podría hacer uso de EqualityComparer<A>.Default.GetHashCode(AValue) (y similar para BValue) aquí, ya que eliminará la necesidad de un cheque nulo.

+0

Debo añadir que hay un conjunto muy importante de reglas OBLIGATORIAS que se deben mantener para que el objeto se comporte correctamente dentro del diccionario. [Implementin Equals()] (http://geekswithblogs.net/gmamaladze/archive/2010/11/27/implementing-the-equals-method-in-.net-and--linear-algebra.aspx) [MSDN al implementar Equals()] (http://msdn.microsoft.com/en-us/library/336aedhh.aspx) –

+1

Otra excelente referencia aquí: http://blogs.msdn.com/b/ericlippert/archive /2011/02/28/guidelines-and-rules-for-gethashcode.aspx – LukeH

0

Estaba anulando la función GetHashCode, pero parece que aunque GetHashCode haya devuelto el mismo valor, la actualización no se realizó. Tener el Equals también, todo es divertido y alegre

Cuestiones relacionadas