2010-03-22 17 views
25

Me encontré con esta situación hoy. Tengo un objeto que estoy probando para la igualdad; el método Create() devuelve una implementación de subclase de MyObject.¿Cuándo puede a == b ser falso y a.Equals (b) verdadero?

MyObject a = MyObject.Create(); 
MyObject b = MyObject.Create(); 

a == b; // is false 
a.Equals(b); // is true 

Nota también tengo Iguales sobre-montado() en la implementación subclase, que hace una comprobación muy básico para ver si el objeto pasado-in es nula y es del tipo de la subclase. Si se cumplen ambas condiciones, los objetos se consideran iguales.

La otra cosa un poco extraña es que mi banco de pruebas unidad hace algunas pruebas similares a

Assert.AreEqual(MyObject.Create(), MyObject.Create()); // Green bar 

y se observa el resultado esperado. Por lo tanto, supongo que NUnit usa a.Equals (b) debajo de las coberturas, en lugar de a == b como lo había supuesto.

Nota al pie: Programa en una mezcla de .NET y Java, por lo que podría estar mezclando mis expectativas/suposiciones aquí. Sin embargo, pensé que a == b funcionaba más uniformemente en .NET que en Java, donde a menudo tienes que usar equals() para probar la igualdad.

ACTUALIZACIÓN Aquí está la aplicación de equals(), como solicitada:

public override bool Equals(object obj) { 
    return obj != null && obj is MyObjectSubclass; 
} 
+3

¿Podríamos ver su implementación de los .Equals() anular – msarchet

+1

? Publique el código para la función Equals anulada. – AxelEckenberger

+0

cuando se anula uno pero no ambos, por supuesto :) – RCIX

Respuesta

32

La diferencia clave entre == y Equals es que == (como todos los operadores) no es polimórfica, mientras Equals (como cualquier función virtual) es.

Por defecto, los tipos de referencia obtendrán resultados idénticos para == y Equals, porque ambos comparan referencias. También es ciertamente posible codificar la lógica de su operador y la lógica Equals de manera completamente diferente, aunque parece absurdo hacerlo. El mayor inconveniente surge cuando se usa el operador == (o cualquiera) en un nivel superior al que se declara la lógica deseada (en otras palabras, haciendo referencia al objeto como una clase padre que no define explícitamente al operador o lo define de manera diferente que el clase verdadera). En tales casos, la lógica para la clase que es hace referencia a como se usa para operadores, pero la lógica para Equals proviene de cualquier clase en que el objeto realmente sea.

Quiero declarar enfáticamente que, basada únicamente en la información en su pregunta, no hay absolutamente ninguna razón para pensar o suponer que Equals compara los valores frente a las referencias. Es trivialmente fácil crear dicha clase, pero esto es no una especificación de idioma.

Post-pregunta-editar editar

Su puesta en práctica de Equals volverá cierto para cualquier instancia no nulo de la clase. Aunque la sintaxis me hace pensar que no, puede confundir la palabra clave is C# (que confirma el tipo) con la palabra clave is en VB.NET (que confirma la igualdad referencial). Si ese es realmente el caso, puede hacer una comparación de referencia explícita en C# utilizando Object.ReferenceEquals(this, obj).

En cualquier caso, esta es la razón por la que está viendo true para Equals, ya que está pasando en una instancia no nula de su clase.

Por cierto, su comentario acerca de NUnit usando Equals es cierto por la misma razón; debido a que los operadores no son polimórficos, no habría forma de que una clase particular defina un comportamiento de igualdad personalizado si la función Assert usó ==.

+0

Esta es la única respuesta correcta hasta el momento – Lee

+4

Esta es posiblemente la mejor respuesta que he tenido a cualquier pregunta que he hecho en el SO. Gracias, Adam, ¡ojalá pudiera votarte más que solo una vez! – alastairs

+1

+1 para direccionar Igual a la anulación después de que el OP haya actualizado la pregunta con el código. –

6

a == b comprueba si hacen referencia al mismo objeto.

a.Equals (b) compara los contenidos.

Esto es link a un artículo de Jon Skeet de 2004 que lo explica mejor.

+1

True for strings. Generalizando para otras clases, 'a.Equals (b)' devuelve el resultado del método Equals de 'a'. –

+0

A menos que sobrecargue el operador ==. +1 –

+4

-1. No hay absolutamente ninguna razón para suponer que "igual" aquí determina la igualdad en base a una inspección profunda de los datos del objeto. –

0

Creo que a == b comprobará si el objeto al que se hace referencia es el mismo.

Por lo general, para ver si el valor es el mismo a.Equals (b) se utiliza (esto a menudo debe ser anulado para poder funcionar).

+1

A menos que la clase anule al operador ==. –

+1

Esto es incorrecto. No hay una diferencia semántica a nivel de lenguaje entre '==' y 'Igual'. –

1

En Java un cheque == b si las referencias de los dos objetos son iguales (rougly, si los dos objetos son el mismo objeto "alias")

a.equals (b) comparar los valores representados por los dos objetos.

+1

Verdadero en Java, no siempre es cierto en C#. –

0

El "==" funciona prueba la igualdad absoluta (a menos que esté sobrecargado); es decir, prueba si dos objetos son el mismo objeto . Eso solo es cierto si asignó uno al otro, es decir.

MyObject a = MyObject.Create(); 
MyObject b = a; 

Simplemente establecer todas las propiedades de dos objetos iguales no significa que los objetos mismos sean. Debajo del capó, lo que el operador "==" está comparando es la dirección de los objetos en la memoria. Un efecto práctico de esto es que si dos objetos son realmente iguales, cambiar una propiedad en uno de ellos también lo cambiará en el otro, mientras que si solo son similares ("igual" igual), no lo hará. Esto es perfectamente consistente una vez que entiendes el principio.

+0

Esto es verdadero * por defecto para tipos de referencia *. No es la verdad absoluta. –

1

Ambos hacen lo mismo a menos que estén específicamente sobrecargados dentro del objeto para hacer otra cosa.

Una cita de Jon Skeet Article mencionada en otro lugar.

El método equals es sólo un Portal definido en System.Object, y anulado por lo que las clases eligen para hacerlo. El operador == es un operador que puede estar sobrecargado por las clases , pero que generalmente tiene un comportamiento de identidad .

La palabra clave aquí es USUALLY. Se pueden escribir para hacer lo que desee la clase subyacente y de ninguna manera tienen que hacer lo mismo.

3

Más o menos, responde a su pregunta a sí mismo:

también tengo más plagado de Iguales() en la implementación subclase, que hace una comprobación muy básico para ver si el pasado-en el objeto es nulo y es del tipo de la subclase. Si se cumplen ambas condiciones, los objetos se consideran iguales.

El operador == no se ha sobrecargado - por lo que está regresando desde falsea y b son diferentes objetos. Pero a.Equals está llamando a su reemplazo, que presumiblemente devuelve true porque ni a ni b son nulos, y ambos son del tipo subclase.

Entonces, la pregunta era "¿Cuándo puede a == b es falsa y a.Equals (b) cierto?" Su respuesta en este caso es: ¡cuando usted lo codifica explícitamente para que así sea!

+1

Como punto de corrección, los operadores están * sobrecargados *, no * anulados * (ya que son estáticos). No hay polimorfismo con los operadores, por lo que aún sería trivialmente fácil producir un escenario donde la lógica idéntica en el operador '==' y el método 'Igual' produciría resultados diferentes. –

+0

Ok, entonces al codificar mis objetos de esta manera, he roto explícitamente Equals/==. ¿Es este un olor de código que indica que el diseño necesita un nuevo pensamiento? – alastairs

+0

@alastairs: * Si desea cualquiera de los dos casos no son nulos de su tipo * que se consideran iguales, entonces usted ha codificado su función correctamente. –

Cuestiones relacionadas