Surchargé est égal à l'opérateur
Il existe en fait une différence de sémantique entre les deux comparaisons lorsque vous comparez null
avec un type qui a surchargé l' ==
opérateur. foo is null
utilisera la comparaison de référence directe pour déterminer le résultat, tandis que foo == null
, bien sûr, exécutera l' ==
opérateur surchargé s'il existe.
Dans cet exemple, j'ai introduit un "bogue" dans l' ==
opérateur surchargé , ce qui lui fait toujours lever une exception si le deuxième argument est 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);
}
// ...
}
Le code IL pour foo is null
utilise l' ceq
instruction pour effectuer une comparaison de référence directe:
IL_0003: ldloc.0 // foo
IL_0004: ldnull
IL_0005: ceq
Le code IL pour foo == null
utilise un appel à l'opérateur surchargé:
IL_0016: ldloc.0 // foo
IL_0017: ldnull
IL_0018: call UserQuery+Foo.op_Equality
La différence est donc que si vous utilisez, ==
vous risquez d'exécuter du code utilisateur (qui peut potentiellement avoir des problèmes de comportement ou de performance inattendus).
Restriction sur les génériques
L'utilisation de la is null
construction limite le type à un type de référence. Le compilateur le garantit, ce qui signifie que vous ne pouvez pas l'utiliser is null
sur un type de valeur. Si vous avez une méthode générique, vous ne pourrez l'utiliser is null
que si le type générique est contraint à être un type de référence.
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
Merci à David Augusto Villa de l' avoir signalé.