c# .net null pattern-matching c#-7.0

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.