c# - ¿Cuál es la diferencia entre "x es nulo" y "x== nulo"?
.net null (2)
En C # 7 podemos usar
if (x is null) return;
en vez de
if (x == null) return;
¿Hay alguna ventaja en usar la nueva forma (ejemplo anterior) sobre la vieja?
¿La semántica es diferente?
¿Es solo cuestión de gustos? Si no, ¿cuándo debo usar uno sobre el otro?
Referencia: Novedades en C # 7.0 .
De hecho, hay una diferencia en la semántica entre las dos comparaciones.
El caso de borde se presenta cuando compara
null
con un tipo que ha sobrecargado el operador
==
.
foo is null
usará una comparación de referencia directa para determinar el resultado, mientras que
foo == null
, por supuesto, ejecutará el operador sobrecargado
==
si existe.
En este ejemplo, he introducido un "error" en el operador
==
sobrecargado, haciendo que siempre arroje una excepción si el segundo argumento es
null
:
void Main()
{
Foo foo = null;
if (foo is null) Console.WriteLine("foo is null"); // This condition is met
if (foo == null) Console.WriteLine("foo == null"); // This will throw an exception
}
public class Foo
{
public static bool operator ==(Foo foo1, Foo foo2)
{
if (object.Equals(foo2, null)) throw new Exception("oops");
return object.Equals(foo1, foo2);
}
// ...
}
El código IL para
foo is null
utiliza la instrucción
ceq
para realizar una comparación de referencia directa:
IL_0003: ldloc.0 // foo
IL_0004: ldnull
IL_0005: ceq
El código IL para
foo == null
usa una llamada al operador sobrecargado:
IL_0016: ldloc.0 // foo
IL_0017: ldnull
IL_0018: call UserQuery+Foo.op_Equality
Entonces, la diferencia es que si usa
==
corre el riesgo de ejecutar código de usuario (que potencialmente puede tener un comportamiento inesperado o problemas de rendimiento).
Actualización:
El compilador de Roslyn se ha actualizado para que el comportamiento de los dos operadores sea el mismo
cuando no hay un operador de igualdad sobrecargado
.
Consulte el
código en los resultados del compilador actual
(
M1
y
M2
en el código) que muestra lo que sucede cuando no hay un comparador de igualdad sobrecargado.
Ambos ahora tienen el mejor comportamiento
==
.
Si hay un comparador de igualdad sobrecargado,
el código sigue siendo diferente
.
Consulte las versiones anteriores del compilador de Roslyn en el análisis a continuación.
Para
null
no hay una diferencia con lo que estamos acostumbrados con C # 6. Sin embargo, las cosas se vuelven interesantes cuando cambia
null
a otra constante.
Toma esto por ejemplo:
Test(1);
public void Test(object o)
{
if (o is 1) Console.WriteLine("a");
else Console.WriteLine("b");
}
La prueba arroja
a
.
Si compara eso con
o == (object)1
lo que habría escrito normalmente, hace una gran diferencia.
is
toma en consideración el tipo en el otro lado de la comparación.
¡Esta genial!
Creo que el patrón
== null
vs.
is null
constante es algo que es muy familiar ''por accidente'', donde la sintaxis del operador
is
y el operador igual producen el mismo resultado.
Como comentó
svick
,
is null
llama a
System.Object::Equals(object, object)
donde
==
llama a
ceq
.
IL para
is
:
IL_0000: ldarg.1 // Load argument 1 onto the stack
IL_0001: ldnull // Push a null reference on the stack
IL_0002: call bool [mscorlib]System.Object::Equals(object, object) // Call method indicated on the stack with arguments
IL_0007: ret // Return from method, possibly with a value
IL para
==
:
IL_0000: ldarg.1 // Load argument 1 onto the stack
IL_0001: ldnull // Push a null reference on the stack
IL_0002: ceq // Push 1 (of type int32) if value1 equals value2, else push 0
IL_0004: ret // Return from method, possibly with a value
Como estamos hablando de
null
, no hay diferencia ya que esto
solo hace una diferencia en las instancias
.
Esto podría cambiar cuando haya sobrecargado el operador de igualdad.