Diferencia de C # entre == e Igual ()

Tengo una condición en una aplicación Silverlight que compara 2 cadenas, por alguna razón cuando uso == devuelve falso, mientras que .Equals() devuelve verdadero .

Aquí está el código:

 if (((ListBoxItem)lstBaseMenu.SelectedItem).Content.Equals("Energy Attack")) { // Execute code } if (((ListBoxItem)lstBaseMenu.SelectedItem).Content == "Energy Attack") { // Execute code } 

¿Alguna razón de por qué esto está sucediendo?

Cuando == se usa en una expresión de tipo object , se resolverá en System.Object.ReferenceEquals .

Equals es solo un método virtual y se comporta como tal, por lo que se utilizará la versión anulada (que, para el tipo de string compara los contenidos).

Al comparar una referencia de objeto a una cadena (incluso si la referencia de objeto hace referencia a una cadena), se ignora el comportamiento especial del operador == específico de la clase de cadena.

Normalmente (cuando no se trata de cadenas, es decir), Equals compara valores , mientras que == compara referencias de objetos . Si dos objetos que está comparando se refieren a la misma instancia exacta de un objeto, ambos serán verdaderos, pero si uno tiene el mismo contenido y proviene de una fuente diferente (es una instancia separada con los mismos datos), solo Equals lo hará regresar verdadero. Sin embargo, como se señala en los comentarios, la cadena es un caso especial porque anula el operador == modo que cuando se trata exclusivamente de referencias de cadena (y no de referencias de objeto), solo se comparan los valores, incluso si son instancias separadas. El siguiente código ilustra las diferencias sutiles en los comportamientos:

 string s1 = "test"; string s2 = "test"; string s3 = "test1".Substring(0, 4); object s4 = s3; Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s2), s1 == s2, s1.Equals(s2)); Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s3), s1 == s3, s1.Equals(s3)); Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s4), s1 == s4, s1.Equals(s4)); 

El resultado es:

 True True True False True True False False True 

== y .Equals dependen del comportamiento definido en el tipo real y el tipo real en el sitio de llamada. Ambos son solo métodos / operadores que pueden ser anulados en cualquier tipo y dado cualquier comportamiento que el autor así lo desee. En mi experiencia, me parece que es común que las personas implementen .Equals en un objeto pero no implementan operator == . Esto significa que .Equals realmente medirá la igualdad de los valores, mientras que == medirá si son la misma referencia o no.

Cuando estoy trabajando con un nuevo tipo cuya definición está en flujo o escribiendo algoritmos generics, encuentro que la mejor práctica es la siguiente

  • Si quiero comparar referencias en C #, uso Object.ReferenceEquals directamente (no es necesario en el caso genérico)
  • Si quiero comparar valores, uso EqualityComparer.Default

En algunos casos, cuando siento que el uso de == es ambiguo, Object.Reference explícitamente Object.Reference es igual en el código para eliminar la ambigüedad.

Eric Lippert recientemente hizo una publicación en el blog sobre el tema de por qué hay dos métodos de igualdad en el CLR. Vale la pena leer

En primer lugar, hay una diferencia. Para números

 > 2 == 2.0 True > 2.Equals(2.0) False 

Y para cuerdas

 > string x = null; > x == null True > x.Equals(null) NullReferenceException 

En ambos casos, == comporta de manera más útil que .Equals

Yo agregaría que si lanzas tu objeto a una cadena, funcionará correctamente. Esta es la razón por la cual el comstackdor le dará una advertencia diciendo:

Posible comparación de referencia no intencional; para obtener una comparación de valores, echa el lado izquierdo para escribir ‘cadena’

== Operador 1. Si los operandos son Tipos de valores y sus valores son iguales, devuelve true else false. 2. Si los operandos son Tipos de Referencia con excepción de la cadena y ambos se refieren al mismo objeto, devuelve true else false. 3. Si los operandos son de tipo cadena y sus valores son iguales, devuelve true else false.

.Equals 1. Si los operandos son Tipos de Referencia, realiza Igualdad de Referencia que si ambos se refieren al mismo objeto, devuelve true else false. 2. Si los Operandos son Tipos de Valor, a diferencia del operador ==, primero verifica su tipo y si sus tipos son iguales, realiza == operator else, devuelve falso.

Por lo que yo entiendo, la respuesta es simple:

  1. == compara referencias de objetos.
  2. .Equals compara el contenido del objeto.
  3. Los tipos de datos de cadena siempre actúan como comparación de contenido.

Espero que esté en lo correcto y que haya respondido tu pregunta.

Estoy un poco confundido aquí. Si el tipo de contenido de tiempo de ejecución es de tipo cadena, ambos == e Igual deben devolver verdadero. Sin embargo, dado que este no parece ser el caso, entonces el tipo de contenido en tiempo de ejecución no es una cadena y llamar a Igual en él está haciendo una igualdad referencial y esto explica por qué Equals (“Energy Attack”) falla. Sin embargo, en el segundo caso, la decisión sobre a qué operador sobrecargado == static se debe llamar se realiza en tiempo de comstackción y esta decisión parece ser == (string, string). esto me sugiere que el Contenido proporciona una conversión implícita a la cadena.

Hay otra dimensión en una respuesta anterior de @BlueMonkMN. La dimensión adicional es que la respuesta a la pregunta del título de @ Drahcir como se establece también depende de cómo llegamos al valor de la string . Para ilustrar:

 string s1 = "test"; string s2 = "test"; string s3 = "test1".Substring(0, 4); object s4 = s3; string s5 = "te" + "st"; object s6 = s5; Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s2), s1 == s2, s1.Equals(s2)); Console.WriteLine("\n Case1 - A method changes the value:"); Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s3), s1 == s3, s1.Equals(s3)); Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s4), s1 == s4, s1.Equals(s4)); Console.WriteLine("\n Case2 - Having only literals allows to arrive at a literal:"); Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s5), s1 == s5, s1.Equals(s5)); Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s6), s1 == s6, s1.Equals(s6)); 

El resultado es:

 True True True Case1 - A method changes the value: False True True False False True Case2 - Having only literals allows to arrive at a literal: True True True True True True 

Añadiendo un punto más a la respuesta.

.EqualsTo() método .EqualsTo() le brinda la posibilidad de comparar con la cultura y las mayúsculas y minúsculas.

Debido a que la versión estática del método .Equal no se mencionó hasta ahora, me gustaría agregar esto aquí para resumir y comparar las 3 variaciones.

 MyString.Equals("Somestring")) //Method 1 MyString == "Somestring" //Method 2 String.Equals("Somestring", MyString); //Method 3 (static String.Equals method) - better 

donde MyString es una variable que proviene de otro lugar en el código.

Información de fondo y summerize:

En Java, usar == para comparar cadenas no debería usarse. Menciono esto en caso de que necesite usar ambos idiomas y también para hacerle saber que el uso de == también puede ser reemplazado por algo mejor en C #.

En C # no hay diferencia práctica para comparar cadenas usando el Método 1 o el Método 2, siempre que ambas sean de tipo cadena. Sin embargo, si uno es nulo, uno es de otro tipo (como un entero), o uno representa un objeto que tiene una referencia diferente, entonces, como muestra la pregunta inicial, puede experimentar que comparar el contenido para la igualdad puede no devolver lo que tu esperas.

Solución sugerida:

Debido a que usar == no es exactamente lo mismo que usar .Equals al comparar cosas, puede usar el método estático String.Equals en su lugar. De esta forma, si las dos partes no son del mismo tipo, igual compararás el contenido y si uno es nulo, evitarás la excepción.

  bool areEqual = String.Equals("Somestring", MyString); 

Es un poco más para escribir, pero en mi opinión, más seguro de usar.

Aquí hay información copiada de Microsoft:

 public static bool Equals (string a, string b); 

Parámetros

a cadena

La primera cadena para comparar, o null .

b Cadena

La segunda cadena para comparar, o null .

Devuelve Boolean

true si el valor de a es el mismo que el valor de b ; de lo contrario, false . Si tanto a como b son null , el método devuelve true .

El símbolo == en C # se usa para dos operadores de verificación de igualdad diferentes. Cuando el comstackdor encuentra ese token, verificará si alguno de los tipos que se comparan ha implementado una sobrecarga del operador de igualdad para los tipos de combinación específicos que se comparan (*) o para una combinación de tipos a los que se pueden convertir ambos tipos. Si el comstackdor encuentra tal sobrecarga, la usará. De lo contrario, si los dos tipos son ambos tipos de referencia y no son clases no relacionadas (ya sea una interfaz o pueden ser clases relacionadas), el comstackdor considerará == como un operador de comparación de referencia. Si no se cumple ninguna condición, la comstackción fallará.

Tenga en cuenta que algunos otros idiomas usan tokens separados para los dos operadores de verificación de igualdad. En VB.NET, por ejemplo, el token = se usa en expresiones únicamente para el operador de verificación de igualdad descargable, y se utiliza como operador de prueba de referencia o prueba nula. Un uso de = en un tipo que no anula el operador de verificación de igualdad fallará, ya que el bash de utilizar Is para cualquier propósito que no sea el de probar la igualdad o nulidad de referencia.

(*) Los tipos generalmente solo sobrecargan la igualdad para su comparación, pero puede ser útil que los tipos sobrecarguen el operador de igualdad para compararlo con otros tipos particulares; por ejemplo, int podría tener (y en mi humilde opinión debería haberlo hecho) un operador de igualdad para compararlo con float , de modo que 16777217 no se reportaría a sí mismo como 16777216f. Tal como está, dado que no se define dicho operador, C # promoverá que el int float , redondeándolo a 16777216f antes de que el operador de verificación de igualdad lo vea; ese operador luego ve dos números de coma flotante iguales y los reporta como iguales, sin darse cuenta del redondeo que tuvo lugar.

¡Excelentes respuestas y ejemplos!

Me gustaría agregar la diferencia fundamental entre los dos,

Los operadores como == no son polimórficos, mientras que Equals es

Con ese concepto en mente, si resuelve cualquier ejemplo (mirando el tipo de referencia de mano izquierda y derecha, y comprobando / sabiendo si el tipo tiene realmente sobrecarga = operador e Igual que sobreescribiendo) está seguro de obtener la respuesta correcta .

Cuando creamos cualquier objeto, hay dos partes en el objeto, una es el contenido y la otra es referencia a ese contenido. == compara contenido y referencia; equals() compara solo el contenido

http://www.codeproject.com/Articles/584128/What-is-the-difference-between-equalsequals-and-Eq

==

El operador == se puede usar para comparar dos variables de cualquier tipo, y simplemente compara los bits .

 int a = 3; byte b = 3; if (a == b) { // true } 

Nota: hay más ceros en el lado izquierdo de la int, pero no nos importa eso aquí.

int a (00000011) == byte b (00000011)

Recuerde == el operador solo se preocupa por el patrón de los bits en la variable.

Use == Si dos referencias (primitivas) se refiere al mismo objeto en el montón.

Las reglas son las mismas si la variable es una referencia o primitiva.

 Foo a = new Foo(); Foo b = new Foo(); Foo c = a; if (a == b) { // false } if (a == c) { // true } if (b == c) { // false } 

a == c es verdadero a == b es falso

el patrón de bits es el mismo para a y c, por lo que son iguales usando ==.

Igual():

Use el método equals () para ver si dos objetos diferentes son iguales .

Como dos objetos String diferentes que representan los personajes de “Jane”

La única diferencia entre Equal y == está en la comparación del tipo de objeto. en otros casos, como los tipos de referencia y los tipos de valores, son casi los mismos (ambos son iguales a los bits o ambos son igualdad de referencia).

objeto: Igualdad: igualdad de bits ==: igualdad de referencia

string: (equals y == son lo mismo para string, pero si uno de string cambia a object, el resultado de la comparación será diferente) Igual a: bit-wise equality ==: bit-wise equality

Mira aquí para más explicaciones.