Überladen ist gleich Operator
Tatsächlich gibt es einen Unterschied in der Semantik zwischen den beiden Vergleichen, wenn Sie null
mit einem Typ vergleichen, der den ==
Operator überlastet hat . foo is null
verwendet einen direkten Referenzvergleich, um das Ergebnis zu bestimmen, während foo == null
der überladene ==
Operator natürlich ausgeführt wird , falls vorhanden.
In diesem Beispiel habe ich einen "Fehler" im überladenen ==
Operator eingeführt, der dazu führt, dass immer eine Ausnahme ausgelöst wird, wenn das zweite Argument lautet 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);
}
// ...
}
Der IL-Code für foo is null
verwendet die ceq
Anweisung, um einen direkten Referenzvergleich durchzuführen:
IL_0003: ldloc.0 // foo
IL_0004: ldnull
IL_0005: ceq
Der IL-Code für foo == null
verwendet einen Aufruf an den überladenen Operator:
IL_0016: ldloc.0 // foo
IL_0017: ldnull
IL_0018: call UserQuery+Foo.op_Equality
Der Unterschied besteht also darin, dass Sie bei Verwendung ==
das Risiko eingehen, Benutzercode auszuführen (was möglicherweise zu unerwartetem Verhalten oder Leistungsproblemen führen kann).
Beschränkung auf Generika
Durch die Verwendung des is null
Konstrukts wird der Typ auf einen Referenztyp beschränkt. Der Compiler stellt dies sicher, was bedeutet, dass Sie nicht is null
für einen Werttyp verwenden können. Wenn Sie über eine generische Methode verfügen, können Sie diese nur verwenden, is null
wenn der generische Typ auf einen Referenztyp beschränkt ist.
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
Vielen Dank an David Augusto Villa für diesen Hinweis.