2010-08-12 17 views
14

tengo el siguiente código:.NET objetos que son iguales no dicen que son

object val1 = 1; 
object val2 = 1; 

bool result1 = (val1 == val2);//Equals false 
bool result2 = val1.Equals(val2); //Equals true 

¿Qué pasa con eso? ¿Es la única forma de arreglar esto para ir con el método .Equals()?

+0

Dicen que son iguales pero hay dos casos diferentes –

+0

Dude, == y .Equals hacen 2 cosas diferentes. == operador comprueba si val1 y val2 ocupan el mismo espacio de memoria (referencia). .Equals comprueba la igualdad de contenido. – Icemanind

+5

También puede usar el método estático 'object.Equals (object, object)', que primero intenta comparar los objetos usando el operador '==' y luego prueba el método 'object.Equals (object)' si ambos parámetros son no nulo. La razón por la que sugiero es para que no tenga que verificar null antes de llamar a 'object.Equals (object, object)', mientras que si llama a 'object.Equals (object)'. –

Respuesta

32

El operador == es estático, no virtual, por lo que el comportamiento está determinado por el tipo estático y no por el tipo de tiempo de ejecución. La implementación predeterminada para == en objetos del tipo de referencia es para comparar las referencias (aunque los tipos pueden implementar un comportamiento diferente, por ejemplo string). Tiene dos objetos diferentes y no tienen la misma referencia, por lo que == devuelve falso.

La solución, como usted señala, es usar Equals. Equals es un método virtual. Como value1 tiene el tipo de tiempo de ejecución Int32, termina llamando al Int32.Equals. De .NET reflector se puede ver que la puesta en práctica de esto es la siguiente:

public override bool Equals(object obj) 
{ 
    return ((obj is int) && (this == ((int) obj))); 
} 

En otras palabras, se comprueba si el argumento es de tipo int, y si es así se proyecta y utiliza el == que se define para int. Esto compara los valores de los enteros.

¿Es la única forma de arreglar esto para ir con el método .Equals()?

Una alternativa es echar sus objetos a int y luego usar ==, al igual que la implementación de Int32.Equals hace.

+0

Esta parece ser la única respuesta correcta (o, al menos, estoy bastante seguro de que puede usar == en una cadena y hacer que funcione como se esperaba). –

+1

Bien, no entiendo por qué * Equals * funciona aquí. De acuerdo con los documentos http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx "La implementación predeterminada de * Equals * admite la igualdad de referencia para los tipos de referencia y la igualdad bit a bit para los tipos de valor. La igualdad de referencia significa el objeto las referencias que se comparan se refieren al mismo * objeto *. " –

+0

@John C: Buena pregunta. ¿Mi respuesta actualizada lo aclara? –

10

Sí. == comprueba la igualdad de referencia. Use Equals donde quiera comparar contenido.

Quizás se pregunte por qué sucede esto con los objetos. Cuando establece un entero (tipo de valor) en una variable de objeto, ocurre una operación llamada boxeo. Esta operación ajusta el tipo de valor en un objeto y lo coloca en el montón y devuelve una referencia. Esto ocurre dos veces y las referencias se vuelven diferentes (aunque los valores son los mismos).

1

Esto se debe a que cuando los convierte en objetos, se "convierten" a referencias a valores int. Y las dos referencias no son iguales. Pero equals compara los valores referenciados en lugar de las referencias.

0

Dos objetos son iguales si apuntan al mismo espacio en la memoria.

val1 == val1; //Equals true 

Como señaló por tc puede hacer una sobrecarga del operador.

public static bool operator ==(Object a, Object b) 

De esta manera el comportamiento del operador == será el definido por este método.

También debe sobrecargar el operador != cuando sobrecarga ==.

+1

A menos que haya una sobrecarga del operador. –

+0

@tc corrigió mi nota. Gracias. –

2

== comprueba si los dos objetos son idénticos. Ellos no son.Representan el mismo número, pero se almacenan en diferentes lugares en la memoria.

Es como comparar dos manzanas. Ambas son manzanas y tienen el mismo aspecto, pero son objetos diferentes.

0

Si no está utilizando object sino una clase personalizada, puede anular el == y! = Operadores, y probablemente debe implementar la interfaz IEqualityComparer<T>

public static bool operator ==(MyType left, MyType right) 
{ 
    //code here, don't forget about NULLS when writing comparison code!!! 
} 

public static bool operator !=(MyType left, MyType right) 
{ 
    return !(left == right); 
} 

public bool Equals(MyType x, MyType y) 
{ 
    return (x == y); 
} 

public int GetHashCode(MyType obj) 
{ 
    return base.GetHashCode(); 
} 
0

El CIL para sus buzones de código los dos enteros y compara los dos objetos que resultan del boxeo (==). Esta comparación es por referencia.

.locals init ([0] object val1, 
      [1] object val2, 
      [2] bool result1, 
      [3] bool result2) 
    IL_0000: nop 
    IL_0001: ldc.i4.1 
    IL_0002: box  [mscorlib]System.Int32 
    IL_0007: stloc.0 
    IL_0008: ldc.i4.1 
    IL_0009: box  [mscorlib]System.Int32 
    IL_000e: stloc.1 
    IL_000f: ldloc.0 
    IL_0010: ldloc.1 
    IL_0011: ceq 
    IL_0013: stloc.2 
    IL_0014: ldloc.0 
    IL_0015: ldloc.1 
    IL_0016: callvirt instance bool [mscorlib]System.Object::Equals(object) 
    IL_001b: stloc.3 

Para los .equals que llama Object.equals, que llama Int32.Equals (llamada a un método virtual en Object):

public override bool Equals(object obj) 
{ 
    return ((obj is int) && (this == ((int) obj))); 
} 

Esto arroja a int y compara los valores como enteros, un valor tipo de comparación.

Cuestiones relacionadas