¿Cuál es la diferencia entre" x es null "y"x == null"?
En C# 7 podemos usar
if (x is null) return;
En lugar de
if (x == null) return;
¿Hay alguna ventaja de usar la nueva forma (ejemplo anterior) que la sintaxis antigua?
La semántica es diferente?
Es solo una cuestión de gusto? Si no, cuándo usar uno u otro.
2 answers
Update: El compilador de Roslyn se ha actualizado para hacer que el comportamiento de los dos operadores sea el mismo cuando no hay un operador de igualdad sobrecargado. Por favor vea el código en los resultados del compilador actual (M1
y M2
en el código) que muestra lo que sucede cuando no hay comparador de igualdad sobrecargado. Ambos ahora tienen el mejor comportamiento ==
. Si hay un comparador de igualdad sobrecargado, el código todavía difiere.
Véase para versiones anteriores del compilador de Roslyn el siguiente análisis.
Para null
no hay una diferencia con lo que estamos acostumbrados con C# 6. Sin embargo, las cosas se vuelven interesantes cuando cambias null
a otra constante.
Tome esto por ejemplo:
Test(1);
public void Test(object o)
{
if (o is 1) Console.WriteLine("a");
else Console.WriteLine("b");
}
La prueba produce a
. Si comparas eso con o == (object)1
lo que habrías escrito normalmente, hace una gran diferencia. is
toma en consideración el tipo en el otro sitio de la comparación. Eso es ¡Órale!
Creo que el patrón constante == null
vs. is null
es solo algo que es muy familiar 'por accidente', donde la sintaxis del operador is
y el operador igual producen el mismo resultado.
Como svick, comentó, is null
llamadas System.Object::Equals(object, object)
donde ==
llamadas 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
Ya que estamos hablando de null
, no hay diferencia desde este solo hace una diferencia en las instancias. Esto podría cambiar cuando se ha sobrecargado el operador de igualdad.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-15 08:28:06
De hecho, hay una diferencia en la semántica entre las dos comparaciones. El caso de borde se presenta cuando se compara null
con un tipo que ha sobrecargado el operador ==
.
foo is null
utilizará la 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 overloaded ==
, haciendo que siempre devuelva false
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 condition is NOT met
}
public class Foo
{
public static bool operator ==(Foo foo1, Foo foo2)
{
if (object.Equals(foo2, null)) return false;
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
utiliza una llamada al operador sobrecargado:
IL_0016: ldloc.0 // foo
IL_0017: ldnull
IL_0018: call UserQuery+Foo.op_Equality
Así que la diferencia es que si usas ==
corres el riesgo de ejecutar código de usuario (que puede ser defectuoso o tener un mal rendimiento).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-12 07:37:02