Operador igual sobrecargado
De hecho, existe una diferencia en la semántica entre las dos comparaciones cuando se compara null
con un tipo que ha sobrecargado al ==
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 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 ceq
instrucción 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
Entonces, la diferencia es que si lo usa ==
, corre el riesgo de ejecutar código de usuario (que potencialmente puede tener problemas inesperados de comportamiento o rendimiento).
Restricción de genéricos.
El uso de la is null
construcción restringe el tipo a un tipo de referencia. El compilador asegura esto, lo que significa que no puede usar is null
un tipo de valor. Si tiene un método genérico, no podrá usarlo a is null
menos que el tipo genérico esté limitado a ser un tipo de referencia.
bool IsNull<T>(T item) => item is null; // Compile error: CS0403
bool IsNull<T>(T item) => item == null; // Works
bool IsNull<T>(T item) where T : class => item is null; // Works
Gracias a David Augusto Villa por señalar esto.