¿Por qué las siguientes expresiones son diferentes?
[1] (object)0 == (object)0 //false
[2] ((object)0).Equals((object)0) // true
De hecho, puedo entender totalmente [1] porque probablemente el tiempo de ejecución de .NET será box
el entero y comenzará a comparar las referencias. Pero, ¿por qué [2] es diferente?
short myShort = 0; int myInt = 0; Console.WriteLine("{0}{1}{2}", myShort.Equals(myInt), myInt.Equals(myShort), myInt == myShort);
Ahora compárelo con la realidad. ¿Tu predicción fue correcta? Si no es así, ¿puede explicar la discrepancia?int16
también conocido comoshort
Equals, luego mire msdn.microsoft.com/en-us/library/ms173105.aspx . No quiero estropear el acertijo de Eric Lippert, pero debería ser bastante fácil de resolver una vez que lea esas páginas.((Integer)0)==((Integer)0)
evalúa como verdadero.IFormattable x = 0; bool test = (object)x == (object)x;
. No se realiza ningún nuevo boxeo cuando la estructura ya está en una caja.Respuestas:
La razón por la que las llamadas se comportan de manera diferente es que se unen a métodos muy diferentes.
El
==
caso se vinculará al operador de igualdad de referencia estática. Seint
crean 2 valores en recuadros independientes , por lo que no son la misma referencia.En el segundo caso, se vincula al método de instancia
Object.Equals
. Este es un método virtual que filtrará y buscaráInt32.Equals
un entero en caja. Ambos valores enteros son 0, por lo tanto, son igualesfuente
==
caso no llamaObject.ReferenceEquals
. Simplemente produce laceq
instrucción IL para realizar una comparación de referencia.==
hace lo mismo queReferenceEquals
(en Object, de todos modos). Todo es optimización interna en el lado de MS para evitar llamadas de función internas innecesarias en funciones de uso frecuente.bool operator ==(object x, object y);
bool operator !=(object x, object y);
Los operadores devuelven el resultado de comparar las dos referencias en busca de igualdad o no igualdad. No es un requisito queSystem.Object.ReferenceEquals
se utilice el método para determinar el resultado. Para @markmnl: No, el compilador de C # no está integrado, eso es algo que el jitter a veces hace (pero no en este caso). Entonces 280Z28 tiene razón, elReferenceEquals
método no se usa realmente.Cat Whiskers; Dog Fido; IDog Fred;
(por interfaces no relacionadosICat
yIDog
clases y no relacionadosCat:ICat
yDog:IDog
), las comparacionesWhiskers==Fido
yWhiskers==34
sería legal (el primero sólo podía ser cierto si las barbas y Fido eran tanto nula, y la segunda nunca podría ser verdad ). De hecho, un compilador de C # rechazará ambos.Whiskers==Fred;
estará prohibido siCat
está sellado, pero permitido si no lo está.Cuando lanza el valor int
0
(o cualquier otro tipo de valor) aobject
, el valor está en un cuadro . Cada lanzamientoobject
produce una caja diferente (es decir, una instancia de objeto diferente). El==
operador delobject
tipo realiza una comparación de referencia, por lo que devuelve falso, ya que el lado izquierdo y el lado derecho no son la misma instancia.Por otro lado, cuando usa
Equals
, que es un método virtual, usa la implementación del tipo en caja real, es decirInt32.Equals
, que devuelve verdadero ya que ambos objetos tienen el mismo valor.fuente
El
==
operador, al ser estático, no es virtual. Ejecutará el código exacto queobject
define la clase (siendo el objeto el tipo de tiempo de compilación de los operandos), que hará una comparación de referencia, independientemente del tipo de tiempo de ejecución de cualquiera de los objetos.El
Equals
método es un método de instancia virtual. Ejecutará el código definido en el tipo de tiempo de ejecución real del (primer) objeto, no el código de laobject
clase. En este caso, el objeto es unint
, por lo que realizará una comparación de valores, ya que eso es lo queint
define el tipo para suEquals
método.fuente
==
token en realidad representa dos operadores, uno de los cuales se puede sobrecargar y el otro no. El comportamiento del segundo operador es muy diferente al de una sobrecarga en (objeto, objeto).El
Equals()
método es virtual.Por lo tanto, siempre llama a la implementación concreta, incluso cuando el sitio de llamadas está dirigido a
object
.int
anula laEquals()
comparación por valor, por lo que obtiene una comparación de valor.fuente
==
Utilizar:Object.ReferenceEquals
Object.Equals
compara el valor.El
object.ReferenceEquals
método compara referencias. Cuando asigna un objeto, recibe una referencia que contiene un valor que indica su ubicación de memoria además de los datos del objeto en el montón de memoria.El
object.Equals
método compara el contenido de los objetos. Primero verifica si las referencias son iguales, al igual que object.ReferenceEquals. Pero luego llama a los métodos Equals derivados para probar más la igualdad. Mira esto:fuente
Object.ReferenceEquals
comporta como un método que usa el==
operador de C # en sus operandos, el operador de operador de igualdad de referencias de C # (que se representa mediante el uso==
de tipos de operandos para los que no se define una sobrecarga) usa una instrucción especial en lugar de llamarReferenceEquals
. Además,Object.ReferenceEquals
aceptará operandos que solo podrían coincidir si ambos resultan ser nulos, y aceptará operandos que deben ser coaccionados por tipoObject
y, por lo tanto, no podrían coincidir con nada, mientras que la versión de igualdad de referencia de==
se negaría a compilar dicho uso. .El operador de C # usa el token
==
para representar dos operadores diferentes: un operador de comparación sobrecargable estáticamente y un operador de comparación de referencia no sobrecargable. Cuando encuentra el==
token, primero verifica si existe alguna sobrecarga de prueba de igualdad que sea aplicable a los tipos de operandos. Si es así, invocará esa sobrecarga. De lo contrario, comprobará si los tipos son aplicables al operador de comparación de referencias. Si es así, utilizará ese operador. Si ningún operador es aplicable a los tipos de operandos, la compilación fallará.El código
(Object)0
no se limita a convertir unInt32
toObject
:Int32
como todos los tipos de valor, en realidad representa dos tipos, uno de los cuales describe valores y ubicaciones de almacenamiento (como el cero literal), pero no se deriva de nada, y uno de los cuales describe amontonar objetos y se deriva deObject
; debido a que solo se puede convertir al último tipoObject
, el compilador debe crear un nuevo objeto de montón de ese último tipo. Cada invocación de(Object)0
crea un nuevo objeto de pila, por lo que los dos operandos==
son objetos diferentes, cada uno de los cuales, de forma independiente, encapsula elInt32
valor 0.La clase
Object
no tiene ninguna sobrecarga utilizable definida para el operador igual. En consecuencia, el compilador no podrá utilizar el operador de prueba de igualdad sobrecargado y volverá a utilizar la prueba de igualdad de referencia. Debido a que los dos operandos se==
refieren a objetos distintos, informaráfalse
. La segunda comparación tiene éxito porque pregunta a una instancia de objeto de montónInt32
si es igual a la otra. Como esa instancia sabe lo que significa ser igual a otra instancia distinta, puede respondertrue
.fuente
0
en su código, asumo que crea un objeto int en el montón para eso. No es una referencia única a un valor cero estático global (como la forma en que hicieron String.Empty para evitar crear nuevos objetos de cadena vacíos solo para inicializar nuevas cadenas) Así que estoy bastante seguro de que incluso hacer un0.ReferenceEquals(0)
devolverá falso, ya que ambos 0 sonInt32
objetos recién creados .0.ReferenceEquals(0)
, fallará porque está intentando llamar a un método en una constante de tiempo de compilación. no hay ningún objeto para colgarlo. Un int sin caja es una estructura, almacenada en la pila. Inclusoint i = 0; i.ReferenceEquals(...)
no funcionará. PorqueSystem.Int32
NO hereda deObject
.System.Int32
es unstruct
, unstruct
esSystem.ValueType
, que en sí mismo heredaSystem.Object
. Por eso hay unToString()
método y unEquals
método paraSystem.Int32
Object
, y ahí es donde dejé de preocuparme por eso hace mucho tiempo. Nunca fue necesario ir más lejos. AFAIK the CLR maneja los dos tipos de manera diferente, y especialmente. No es solo herencia. Sinis
embargo, es uno de los dos tipos de datos. Simplemente no quería que nadie leyera ese comentario y se desviara tanto, incluida la extrañeza de las cadenas vacías que ignora la práctica de cadenas.Ambos controles son diferentes. El primero comprueba la identidad , el segundo la igualdad . En general, dos términos son idénticos si se refieren al mismo objeto. Esto implica que son iguales. Dos términos son iguales, si sus valores son iguales.
En términos de programación, la identidad suele estar dividida por la igualdad de referencias. Si el puntero a ambos términos es igual (!), El objeto al que apuntan es exactamente el mismo. Sin embargo, si los punteros son diferentes, el valor de los objetos a los que apuntan puede ser igual. En C #, la identidad se puede verificar usando el
Object.ReferenceEquals
miembro estático , mientras que la igualdad se verifica usando elObject.Equals
miembro no estático . Dado que está lanzando dos enteros a objetos (lo que se llama "boxeo", por cierto), el operador==
deobject
realiza la primera verificación, que está asignada por defectoObject.ReferenceEquals
y verifica la identidad. Si llama explícitamente alEquals
miembro no estático , el envío dinámico da como resultado una llamada aInt32.Equals
, que verifica la igualdad.Ambos conceptos son similares, pero no iguales. Pueden parecer confusos al principio, ¡pero la pequeña diferencia es muy importante! Imagínese dos personas, a saber, "Alice" y "Bob". Ambos viven en una casa amarilla. Basado en la suposición de que Alice y Bob viven en un distrito, donde las casas solo difieren en su color, ambos podrían vivir en diferentes casas amarillas. Si comparas ambas casas, reconocerás que son absolutamente iguales, ¡porque ambas son amarillas! Sin embargo, no comparten la misma casa y, por lo tanto, sus casas son iguales , pero no idénticas . La identidad implicaría que viven en la misma casa.
Nota : algunos idiomas están definiendo al
===
operador para verificar la identidad.fuente