No hay una respuesta simple para esta pregunta. Cualquiera que diga siempre usar uno u otro le está dando malos consejos, en mi opinión.
En realidad, hay varios métodos diferentes que puede llamar para comparar instancias de objetos. Dados dos instancias de objeto a
y b
, se podría escribir:
Object.Equals(a,b)
Object.ReferenceEquals(a,b)
a.Equals(b)
a == b
Todo ello podría hacer cosas diferentes!
Object.Equals(a,b)
será (por defecto) realizar la comparación de igualdad de referencia sobre los tipos de referencia y comparación bit a bit de los tipos de valor.A partir de la documentación de MSDN:
La implementación predeterminada de Iguales apoya la igualdad de referencia para tipos de referencia, y la igualdad bit a bit de los tipos de valor. La igualdad de referencia significa que las referencias de objeto que son comparadas se refieren al mismo objeto. Igualdad por bit significa que los objetos que se comparan tienen la misma representación binaria de .
Tenga en cuenta que un tipo derivado puede anular el método Equals a implementar valor de igualdad. Valor igualdad significa que los objetos comparados tienen el mismo valor pero diferentes representaciones binarias .
Tenga en cuenta el último párrafo anterior ... hablaremos de esto un poco más adelante.
Object.ReferenceEquals(a,b)
realiza la comparación de igualdad de referencia solamente. Si los tipos pasados son tipos de valores encuadrados, el resultado siempre es false
.
a.Equals(b)
llama al método instancia virtual de Object
, que el tipo de a
podría reemplazar a hacer lo que quiera. La llamada se realiza mediante el despacho virtual, por lo que el código que se ejecuta depende del tipo de tiempo de ejecución a
.
a == b
invoca el operador sobrecargado estática del tiempo de compilación ** * Tipo de a
. Si la implementación de ese operador invoca métodos de instancia en a
o b
, también puede depender de los tipos de tiempo de ejecución de los parámetros. Dado que el envío se basa en los tipos en la expresión, lo siguiente puede dar resultados diferentes:
Frog aFrog = new Frog();
Frog bFrog = new Frog();
Animal aAnimal = aFrog;
Animal bAnimal = bFrog;
// not necessarily equal...
bool areEqualFrogs = aFrog == bFrog;
bool areEqualAnimals = aAnimal = bAnimal;
Así que, sí, no es la vulnerabilidad de comprobación de valores nulos utilizando operator ==
. En la práctica, la mayoría de los tipos no sobrecarga ==
- pero nunca hay una garantía.
El método de instancia Equals()
no es mejor aquí. Si bien la implementación predeterminada realiza comprobaciones de referencia/igualdad de bits, es posible que un tipo anule el método del miembro Equals()
, en cuyo caso se llamará a esta implementación. Una implementación suministrada por el usuario podría devolver lo que quiera, incluso cuando se compara con nulo.
¿Pero qué pasa con la versión estática de Object.Equals()
que pides? ¿Esto puede terminar ejecutando el código de usuario? Bueno, resulta que la respuesta es SÍ. La implementación de Object.Equals(a,b)
amplía a algo a lo largo de las líneas de:
((object)a == (object)b) || (a != null && b != null && a.Equals(b))
Puede probar esto por sí mismo:
class Foo {
public override bool Equals(object obj) { return true; } }
var a = new Foo();
var b = new Foo();
Console.WriteLine(Object.Equals(a,b)); // outputs "True!"
Como consecuencia, es posible que la declaración: Object.Equals(a,b)
para ejecutar código de usuario cuando ninguno de los tipos en la llamada son null
.Tenga en cuenta que Object.Equals(a,b)
no llama a la versión de instancia de Equals()
cuando cualquiera de los argumentos es nulo.
En resumen, el tipo de comportamiento de comparación que usted obtiene puede variar significativamente, dependiendo del método que elija para llamar. Un comentario aquí, sin embargo: Microsoft no documenta oficialmente el comportamiento interno de Object.Equals(a,b)
. Si necesita un gaurantee revestido de comparar una referencia a nula y sin ningún otro tipo de código en ejecución hierro, desea Object.ReferenceEquals()
:
Object.ReferenceEquals(item, null);
Este método hace que la intención extremently clara - usted está esperando específicamente que el resultado sea la comparación de dos referencias para la igualdad de referencia. La ventaja aquí sobre el uso de algo así como Object.Equals(a,null)
, es que es menos probable que alguien va a llegar más tarde y decir:
"Hey, esto es incómodo, vamos a sustituirlo por: a.Equals(null)
o a == null
que potencialmente puede ser diferente.
vamos a inyectar algo de pragmatismo aquí, sin embargo. hasta ahora hemos hablado de la posibilidad de que diferentes modalidades de comparación para producir resultados diferentes. Si bien esto es ciertamente el caso, hay ciertos tipos de donde es seguro para wr ite a == null
. Las clases incorporadas de .NET como String
y Nullable<T>
tienen una semántica bien definida para la comparación. Además, son sealed
, evitando cualquier cambio en su comportamiento a través de la herencia. La siguiente es bastante común (y correcta):
string s = ...
if(s == null) { ... }
Es innecesario (y feo) para escribir:
if(ReferenceEquals(s,null)) { ... }
Así que en ciertos casos limitados, utilizando ==
es seguro y apropiado.
Pensé que mi respuesta (la respuesta de Microsoft por proxy) es una respuesta bastante simple. – mquander
Preguntas como: * "debería siempre/nunca hacer X" * implican una falta de conocimiento sobre los matices del tema en cuestión. Sentí que un poco más de detalle sería útil aquí para aclarar por qué no creo que una respuesta simple sea significativa. – LBushkin
El método estático 'object.Equals (a, b)' puede, de hecho, llamar al método 'Equals' sobrecargado/virtual en el objeto' a'. Si recuerdo correctamente, hace algo como '((objeto) a == (objeto) b) || (a! = null && b! = null && a.Equals (b)) '. (Esto es irrelevante cuando se compara con 'null', que es lo que el OP pregunta, pero es relevante para el caso general.) – LukeH