Tengo una condición en una aplicación de Silverlight que compara 2 cadenas, por alguna razón cuando la uso ==
devuelve false mientras .Equals()
devuelve true .
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é sucede esto?
==
, pero los operadores no son polimórficos. En este código, el==
operador se invoca en tipoobject
, que hace una comparación de identidad en lugar de un valor.==
sobrecarga basada en el tipo de tiempo de compilación de los operandos. ElContent
inmueble esobject
. Los operadores no son virtuales, por lo que==
se llama a la implementación predeterminada de , que ofrece una comparación de igualdad de referencia. Con Equals, la llamada va al método virtualobject.Equals(object)
;string
anula este método y realiza una comparación ordinal en el contenido de la cadena. Consulte msdn.microsoft.com/en-us/library/fkfd9eh8(v=vs.110).aspx y referencesource.microsoft.com/#mscorlib/system/string.cs,507 .==
tiene tipo de tiempo de compilaciónobject
y el lado derecho tiene tipo de tiempo de compilaciónstring
, entonces el compilador de C # debe elegir la sobrecarga (problemática, en este caso)operator ==(object, object)
; pero se emita una advertencia de tiempo de compilación que podría ser no intencionados. ¡Entonces lea las advertencias en tiempo de compilación! Para solucionar el problema y seguir usándolo==
, eche el lado izquierdo astring
. Si no recuerdo mal, el texto de advertencia sugiere exactamente eso.Respuestas:
Cuando
==
se usa en una expresión de tipoobject
, se resolveráSystem.Object.ReferenceEquals
.Equals
es solo unvirtual
método y se comporta como tal, por lo que se utilizará la versión anulada (que, porstring
tipo, compara los contenidos).fuente
object
tipo (observe la fuente monoespaciada) está técnicamente destinado a ser "una expresión de tipoSystem.Object
". No tiene nada que ver con el tipo de tiempo de ejecución de la instancia a la que hace referencia la expresión. Creo que la afirmación "los operadores definidos por el usuario son tratados comovirtual
métodos" es extremadamente engañosa. Se tratan como métodos sobrecargados y solo dependen del tipo de tiempo de compilación de los operandos. De hecho, después de calcular el conjunto de operadores candidatos definidos por el usuario, el resto del procedimiento de enlace será exactamente el algoritmo de resolución de sobrecarga del métodovirtual
resolución del método depende del tipo de tiempo de ejecución real de una instancia, mientras que eso se ignora por completo en la resolución de sobrecarga del operador, y ese es realmente el punto central de mi respuesta.Al comparar una referencia de objeto a una cadena (incluso si la referencia de objeto se refiere 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==
compara referencias de objetos . Si dos objetos que está comparando se refieren a la misma instancia exacta de un objeto, ambos devolverán verdadero, 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á volver verdadero. Sin embargo, como se señaló en los comentarios, la cadena es un caso especial porque anula el==
operador, de modo que cuando se trata únicamente de referencias de cadena (y no referencias de objeto), solo se comparan los valores, incluso si son instancias separadas. El siguiente código ilustra las sutiles diferencias en los comportamientos:El resultado es:
fuente
==
y.Equals
ambos dependen del comportamiento definido en el tipo real y el tipo real en el sitio de la llamada. Ambos son solo métodos / operadores que se pueden anular en cualquier tipo y dar cualquier comportamiento que el autor desee. En mi experiencia, encuentro que es común que las personas implementen.Equals
en un objeto pero descuidan implementar el operador==
. Esto significa que en.Equals
realidad medirá la igualdad de los valores mientras==
medirá si son o no la misma referencia.Cuando estoy trabajando con un nuevo tipo cuya definición está en flujo o escribiendo algoritmos genéricos, la mejor práctica es la siguiente
Object.ReferenceEquals
directamente (no es necesario en el caso genérico)EqualityComparer<T>.Default
En algunos casos, cuando siento que el uso de
==
es ambiguo, usaré explícitamenteObject.Reference
iguales en el código para eliminar la ambigüedad.Eric Lippert recientemente hizo una publicación de blog sobre el tema de por qué hay 2 métodos de igualdad en el CLR. Vale la pena leer
fuente
== Operador
Igual
fuente
==
operador puede sobrecargarse para cualquier tipo, no solo cadena. Describir una excepción de caso especial solo para cadenas tergiversa la semántica del operador. Sería más preciso, aunque tal vez no terriblemente útil, decir "si los operandos son tipos de referencia, devuelve verdadero si los operandos se refieren al mismo objeto, a menos que haya una sobrecarga aplicable, en cuyo caso la implementación de esa sobrecarga determina el resultado ". Lo mismo es ciertoEquals
con la complicación adicional de que es un método virtual, por lo que su comportamiento puede anularse y sobrecargarse.En primer lugar, no es una diferencia. Para números
Y para cuerdas
En ambos casos, se
==
comporta de manera más útil que.Equals
fuente
==
operador sea algo bueno. Por ejemplo, ¿debería 16777216.0f igual (int) 16777217, (doble) 16777217.0, ambos o ninguno? Las comparaciones entre tipos integrales están bien, pero las comparaciones de punto flotante solo se deben realizar en mi humilde opinión con valores explícitamente convertidos en tipos coincidentes. La comparación de afloat
con algo diferente a afloat
, odouble
a algo diferente a adouble
, me parece un olor a código importante que no debería compilarse sin diagnósticos.x == y
no implicax/3 == y/3
(intentex = 5
yy = 5.0
)./
la división entera es un defecto en el diseño de C # y Java. Sin embargo, Pascaldiv
e incluso VB.NET's` are much better. The problems with
== `son peores:x==y
yy==z
no implica esox==z
(considere los tres números en mi comentario anterior). En cuanto a la relación que sugiere, incluso six
yy
son ambosfloat
o ambosdouble
,x.equals((Object)y)
no implica que1.0f/x ==
1.0f / a '(si tuviera mis druthers, lo garantizaría; incluso si==
no distingue entre positivo y cero,Equals
debería).Por lo que yo entiendo, la respuesta es simple:
==
compara referencias de objetos..Equals
compara el contenido del objeto.String
los tipos de datos siempre actúan como comparación de contenido.Espero estar en lo cierto y que haya respondido a tu pregunta.
fuente
Agregaría que si arroja su objeto a una cadena, funcionará correctamente. Es por eso que el compilador le dará una advertencia que dice:
fuente
object expr = XXX; if (expr == "Energy") { ... }
, como el lado izquierdo es del tipo de tiempo de compilaciónobject
, el compilador tiene que usar la sobrecargaoperator ==(object, object)
. Comprueba la igualdad de referencia. Si eso darátrue
ofalse
puede ser difícil de predecir debido al internamiento de cadenas . Si sabe que el lado izquierdo esnull
de tipo ostring
, escriba el lado izquierdostring
antes de usar==
.Debido a que la versión estática del
.Equal
método no se mencionó hasta ahora, me gustaría agregar esto aquí para resumir y comparar las 3 variaciones.donde
MyString
es una variable que viene de otra parte del código.Información de fondo y para verano:
En Java, usar
==
para comparar cadenas no debe usarse. Menciono esto en caso de que necesite usar ambos idiomas y también para hacerle saber que el uso==
también se puede reemplazar con 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 número entero), o uno representa un objeto que tiene una referencia diferente, entonces, como lo muestra la pregunta inicial, puede experimentar que comparar el contenido para la igualdad no devuelva lo que tu esperas.
Solución sugerida:
Debido a que usar
==
no es exactamente lo mismo que usar.Equals
al comparar cosas, puedes usar el método estático String.Equals en su lugar. De esta manera, si los dos lados no son del mismo tipo, todavía comparará el contenido y si uno es nulo, evitará la excepción.Es un poco más para escribir, pero en mi opinión, es más seguro de usar.
Aquí hay información copiada de Microsoft:
Parámetros
a
CuerdaLa primera cadena para comparar, o
null
.b
CuerdaLa segunda cadena para comparar, o
null
.Devoluciones
Boolean
true
si el valor dea
es el mismo que el valor deb
; de lo contrario,false
. Si ambosa
yb
sonnull
, el método regresatrue
.fuente
Solo como una adición a las respuestas ya buenas: este comportamiento NO se limita a las cadenas o la comparación de diferentes tipos de números. Incluso si ambos elementos son de tipo objeto del mismo tipo subyacente. "==" no funcionará.
La siguiente captura de pantalla muestra los resultados de comparar dos objetos {int} - valores
fuente
Estoy un poco confundido aquí. Si el tipo de contenido de tiempo de ejecución es de tipo cadena, entonces ambos == y Equals deberían devolver verdadero. Sin embargo, dado que este no parece ser el caso, entonces el tipo de contenido de tiempo de ejecución no es una cadena y llamar a Iguales es una igualdad referencial y esto explica por qué falla Equals ("Energy Attack"). Sin embargo, en el segundo caso, la decisión sobre qué operador sobrecargado == estático debería llamarse en tiempo de compilación y esta decisión parece ser == (cadena, cadena). Esto me sugiere que el Contenido proporciona una conversión implícita a cadena.
fuente
Hay otra dimensión a una respuesta anterior de @BlueMonkMN. La dimensión adicional es que la respuesta a la pregunta del título de @ Drahcir como se dice también depende de cómo llegamos al
string
valor. Para ilustrar:El resultado es:
fuente
Agregar un punto más a la respuesta.
.EqualsTo()
El método le brinda la posibilidad de comparar con la cultura y mayúsculas y minúsculas.fuente
El
==
token en C # se usa para dos operadores diferentes de verificación de igualdad. Cuando el compilador encuentra ese token, verificará si alguno de los tipos comparados ha implementado una sobrecarga de operador de igualdad para los tipos de combinación específicos que se comparan (*) o para una combinación de tipos a los que ambos tipos se pueden convertir. Si el compilador encuentra una sobrecarga, la usará. De lo contrario, si los dos tipos son ambos tipos de referencia y no son clases no relacionadas (pueden ser una interfaz o pueden ser clases relacionadas), el compilador lo considerará==
como un operador de comparación de referencias. Si ninguna de las condiciones se aplica, la compilació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 dentro de expresiones únicamente para el operador de verificación de igualdad sobrecargable, yIs
se usa como operador de prueba de referencia o de prueba nula. Un uso=
en un tipo que no anula el operador de verificación de igualdad fallará, al igual que intentar usarloIs
para cualquier propósito que no sea probar la igualdad o nulidad de referencia.(*) Los tipos generalmente solo sobrecargan la igualdad para comparación con ellos mismos, pero puede ser útil para los tipos sobrecargar el operador de igualdad para la comparación con otros tipos particulares; por ejemplo,
int
podría haber (y en mi humilde opinión debería haberlo definido, pero no lo hizo) un operador de igualdad para compararlofloat
, de modo que 16777217 no se reportaría igual a 16777216f. Tal como están las cosas, dado que dicho operador no está definido, C # promoverá elint
tofloat
, redondeándolo a 16777216f antes de que el operador de verificación de igualdad lo vea; ese operador luego ve dos números iguales de punto flotante y los informa como iguales, sin darse cuenta del redondeo que tuvo lugar.fuente
3
como igual a3.0f
. Si requerimos que el programador diga lo que se pretende en cada caso, entonces no hay peligro de que el comportamiento predeterminado conduzca a resultados no deseados, ya que no existe un comportamiento predeterminado.Realmente excelentes respuestas y ejemplos!
Solo me gustaría agregar la diferencia fundamental entre los dos,
Con ese concepto en mente, si resuelve algún ejemplo (mirando el tipo de referencia de la mano izquierda y derecha, y verificando / sabiendo si el tipo realmente tiene == operador sobrecargado y Equals siendo anulado), seguramente obtendrá la respuesta correcta .
fuente
Cuando creamos cualquier objeto hay dos partes en el objeto, una es el contenido y la otra es referencia a ese contenido.
==
compara tanto el contenido como la referencia;equals()
compara solo contenidohttp://www.codeproject.com/Articles/584128/What-is-the-difference-between-equalsequals-and-Eq
fuente
a
yb
son ambas referencias de cadena, el resultado dea == b
no depende de si las referencias apuntan al mismo objeto.==
El operador == puede usarse para comparar dos variables de cualquier tipo, y simplemente compara los bits .
Nota: hay más ceros en el lado izquierdo del int pero no nos importa eso aquí.
int a (00000011) == byte b (00000011)
Recuerde que el operador == solo se preocupa por el patrón de los bits en la variable.
Use == Si dos referencias (primitivas) se refieren al mismo objeto en el montón.
Las reglas son las mismas tanto si la variable es una referencia como si es primitiva.
a == c es verdadero a == b es falso
los patrones de bits son los mismos para ayc, 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"
fuente
object a = 3; object b = 3; Console.WriteLine(a == b);
. La salida es falsa, aunque los patrones de bits de los valores son los mismos. Los tipos de los operandos también importan. La razón por la que "no nos importa" la cantidad diferente de ceros en su ejemplo es que cuando llamamos al operador igual, la cantidad de ceros es realmente la misma , debido a la conversión implícita.La única diferencia entre Igual y == está en la comparación del tipo de objeto. en otros casos, como los tipos de referencia y los tipos de valor, son casi iguales (ambos son igualdad de bits o ambos son igualdad de referencia).
objeto: igual: igualdad de bits ==: igualdad de referencia
cadena: (igual y == son lo mismo para la cadena, pero si una de la cadena cambia a objeto, entonces el resultado de la comparación será diferente) Igual: igualdad de bits ==: igualdad de bits
Ver aquí para más explicaciones.
fuente