Usar objeto personalizado como clave de diccionario

Quiero usar un objeto personalizado como clave de diccionario, principalmente, tengo algo como esto: (No puedo usar .net 4.0, así que no tengo tuplas)

class Tuple : IEquatable<Tuple> { public A AValue { get; set; } public B BValue { get; set; } public Tuple(A a, B b){ AValue = a; BValue = b; } public bool Equals(Tuple tuple) { return tuple.AValue.Equals(AValue) && tuple.BValue.Equals(BValue); } public bool Equals(object o) { return this.Equals(o as Tuple); } } 

Entonces hago algo como esto.

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

Obtengo una excepción de KeyNotFound en la última línea. Por qué es esto ? ¿No es suficiente implementar IEquatable?

Gracias

También debe anular GetHashCode() (y preferiblemente también es Equals() ). De lo contrario, su objeto igual está devolviendo 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 su 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, también puede utilizar una lista plana desde una perspectiva de rendimiento).

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

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

Tenga en cuenta que podría ser una buena idea probar si AValue o BValue son null . (Esto será algo complicado ya que no restringes los tipos generics A y B , por lo que no puedes comparar los valores con un valor null , por ejemplo, los tipos podrían ser tipos de valor). 1

También es una buena idea hacer que las clases que pretendes usar como claves de diccionario sean inmutables. Si cambia el valor de un objeto que se está utilizando como una clave, el diccionario mostrará un comportamiento extraño ya que el objeto ahora está en un cubo donde no pertenece.


1 Tenga en cuenta que podría utilizar EqualityComparer.Default.GetHashCode(AValue) (y similar para BValue ) aquí, ya que eliminará la necesidad de una comprobación nula.

GetHashCode anular GetHashCode cuando anula el método Equals. Más explicación se puede encontrar aquí:

¿Por qué es importante anular GetHashCode cuando se invalida el método Equals?

Estaba anulando la función GetHashCode , pero parece que a pesar de que GetHashCode devolvió el mismo valor, la actualización no se realizó. Tener los Equals también, todo es divertido y divertido.