2012-03-07 14 views
6

Digamos que tenemos esta clase:Conversión implícita de un objeto de cadena, para su uso en un Hashtable

public class Moo 
{ 
    string _value; 

    public Moo(string value) 
    { 
     this._value = value; 
    } 

    public static implicit operator string(Moo x) 
    { 
     return x._value; 
    } 

    public static implicit operator Moo(string x) 
    { 
     return new Moo(x); 
    } 

    public override bool Equals(object obj) 
    { 
     if (obj is string) 
      return this._value == obj.ToString(); 
     else if (obj is Moo) 
      return this._value == ((Moo)obj)._value; 
     return base.Equals(obj); 
    } 

    public override int GetHashCode() 
    { 
     return _value.GetHashCode(); 
    } 
} 

Si añado un objeto de este tipo a una tabla hash, entonces puedo encontrar el objeto con la cuerda idéntica.
Pero si la Hashtable contiene la cadena, no el objeto, no lo encuentra cuando paso el objeto.

Moo moo = new Moo("abc"); 
bool result1 = moo == "abc";     //true 
bool result1a = moo.Equals("abc");    //true 
bool result2 = "abc" == moo;     //true 
bool result2a = "abc".Equals(moo);    //true 
bool result2b = ((object)"abc").Equals(moo); //false 

Hashtable hash = new Hashtable(); 
hash[moo] = 100; 
object result3 = hash[moo];      //100 
object result4 = hash["abc"];     //100 

hash = new Hashtable(); 
hash["abc"] = 100; 
object result5 = hash[moo];      //null!!!! 
object result6 = hash["abc"];     //100 

He intentado reemplazar al operador == y no hizo ninguna diferencia.
¿Es posible utilizar la conversión implícita en una Hashtable de esta manera?

+2

Está violando una de las propiedades esenciales de Equals: "x.Equals (y) devuelve el mismo valor que y.Equals (x)." – CodesInChaos

Respuesta

5

En primer lugar, ¿por qué usa una tabla hash en lugar de una genérica Dictionary<,>?

De todos modos, su problema es que la tabla hash llama al ((object)"abc").Equals(moo), que devuelve falso, por supuesto. Puede anular ese comportamiento pasando su propia implementación de IEqualityComparer a uno de los constructores HashTable con un parámetro IEqualityComparer.

Dado que, como ha notado, está tratando de evitar modificar el código heredado, es posible que no pueda reemplazar la tabla hash existente por una que tenga un IEqualityComparer personalizado. Si eso es cierto, entonces creo que la respuesta es que no puedes hacer lo que te gustaría hacer.

Como está desarrollando esta clase "moo", supongo que tiene control sobre el código que pasa la clase moo al indexador de la tabla hash. Si eso es cierto, puede llamar al ToString() en el objeto que está pasando al indexador y, por supuesto, anular ToString en Moo.

+1

No, "abc" .Equals (moo) devuelve verdadero. Y estoy atascado usando Hashtable porque estoy tratando de cambiar el código heredado sin tener que, por ejemplo, cambiar el código. – demoncodemonkey

+2

'" abc ".Equals (moo)' devuelve verdadero para mí. Si asigna 'moo' a una instancia' object' aunque - '" abc ".Equals (mooObj)' devuelve false. – BrokenGlass

+3

@demoncodemonkey: '" abc ".Equals (moo)' solo devuelve verdadero porque el compilador está realizando la sobrecarga del operador, que conoce acerca de * en tiempo de compilación *. Pruebe '((object)" abc "). Equals (moo)' para ver lo que hará la Hashtable. –

4

Por lo tanto, los moldes implícitos son irrelevantes. Ellos no harán nada. Obtendrá exactamente los mismos resultados si los comenta. Lo que importa aquí son los métodos Equal y GetHashCode.

Así que su método GetHashCode está bien. Dos objetos (ya sea una cadena o un moo) siempre tendrán el mismo hash si deben ser iguales, por lo que funcionará. Tu problema es con tu método igual.

moo.Equals("abc") devolverá verdadero.

object obj = moo; 
"abc".Equals(obj) 

devolverá falso; "abc".Equals(moo) devolverá verdadero solo porque hay un operador implícito que convierte moo en una cadena, y utiliza la sobrecarga de cadena de Equals, en lugar de la sobrecarga de objetos de Equals. Como Hashtable va a almacenar todo como un objeto, siempre usará la sobrecarga object del método Equals. (El operador == no se utiliza; utiliza el método Equals en el diccionario). Esto se debe a que el método Equals de la cadena se comprobará para asegurarse de que el objeto pasado es una cadena, y devolverá falso si no es así.

La solución: No necesita usar el constructor predeterminado de HashTable. Lo que debe hacer es usar un IEqualityComparor personalizado para que no use el método Equals del objeto en sí. Esto no es muy difícil de hacer. Solo cree una nueva clase que extienda IEqualityComparer y asígnele un método igual que sea básicamente el mismo que el método Equals de su moo para que realice la comparación correctamente independientemente de qué tipo lo objeta.

+0

No, "abc" .Equals (moo) devuelve verdadero, me temo. – demoncodemonkey

+0

Entonces eso se debe a la conversión implícita, que no será posible con una tabla hash. 'object obj = moo; "abc" .Equals (obj) 'devolverá false – Servy

+1

He ampliado la respuesta para incorporar una mejor explicación de lo que está haciendo llamadas a' Equals'. – Servy

Cuestiones relacionadas