Wie prüfe ich für NULL-Werte in einer ‚==‘ Operator Überlastung ohne unendliche Rekursion?
-
09-06-2019 - |
Frage
Im Folgenden wird eine unendliche Rekursion auf dem Operator == Überlast-Methode führen
Foo foo1 = null;
Foo foo2 = new Foo();
Assert.IsFalse(foo1 == foo2);
public static bool operator ==(Foo foo1, Foo foo2) {
if (foo1 == null) return foo2 == null;
return foo1.Equals(foo2);
}
Wie kann ich für NULL-Werte überprüfen?
Lösung
Verwenden ReferenceEquals
:
Foo foo1 = null;
Foo foo2 = new Foo();
Assert.IsFalse(foo1 == foo2);
public static bool operator ==(Foo foo1, Foo foo2) {
if (object.ReferenceEquals(null, foo1))
return object.ReferenceEquals(null, foo2);
return foo1.Equals(foo2);
}
Andere Tipps
Cast in Überlast Methode zum Objekt:
public static bool operator ==(Foo foo1, Foo foo2) {
if ((object) foo1 == null) return (object) foo2 == null;
return foo1.Equals(foo2);
}
Mit ReferenceEquals
. Von der MSDN Foren :
public static bool operator ==(Foo foo1, Foo foo2) {
if (ReferenceEquals(foo1, null)) return ReferenceEquals(foo2, null);
if (ReferenceEquals(foo2, null)) return false;
return foo1.field1 == foo2.field2;
}
Versuchen Object.ReferenceEquals(foo1, null)
Wie auch immer, ich würde nicht empfehlen, die ==
operator Überlastung; es sollte für den Vergleich von Referenzen verwendet werden, und verwenden Sie Equals
für „semantische“ Vergleiche.
Wenn ich bool Equals(object obj)
overrided haben und ich möchte den Betreiber ==
und Foo.Equals(object obj)
die gleiche Antwort zurück, ich in der Regel die !=
Operator wie folgt implementieren:
public static bool operator ==(Foo foo1, Foo foo2) {
return object.Equals(foo1, foo2);
}
public static bool operator !=(Foo foo1, Foo foo2) {
return !object.Equals(foo1, foo2);
}
Der Betreiber ==
wird dann schließlich die Null Kontrollen zu tun für mich so zu nennen foo1.Equals(foo2)
am Ende, dass ich außer Kraft gesetzt haben, die eigentliche Prüfung zu tun, wenn die beiden gleich sind.
Wenn Sie C # 7 oder höher verwenden können Sie null konstanten Musterabgleich verwenden:
public static bool operator==(Foo foo1, Foo foo2)
{
if (foo1 is null)
return foo2 is null;
return foo1.Equals(foo2);
}
Das gibt Ihnen etwas sauberere Code als den einen Aufruf object.ReferenceEquals (foo1, null)
Mein Ansatz ist zu tun
(object)item == null
, auf das ich auf object
eigenen Gleichheitsoperator angewiesen, die nicht schief gehen können. Oder eine benutzerdefinierte Erweiterungsmethode (und eine Überlast):
public static bool IsNull<T>(this T obj) where T : class
{
return (object)obj == null;
}
public static bool IsNull<T>(this T? obj) where T : struct
{
return !obj.HasValue;
}
oder mehr Fälle zu behandeln, kann sein:
public static bool IsNull<T>(this T obj) where T : class
{
return (object)obj == null || obj == DBNull.Value;
}
Die Einschränkung verhindert IsNull
auf Werttypen. Nun ist es so süß wie der Aufruf von
object obj = new object();
Guid? guid = null;
bool b = obj.IsNull(); // false
b = guid.IsNull(); // true
2.IsNull(); // error
das heißt, ich habe eine konsistente / nicht-fehleranfälligen Art während für NULL-Werte zu prüfen. Ich habe auch (object)item == null
ist sehr sehr sehr geringfügig schneller als Object.ReferenceEquals(item, null)
, aber nur, wenn es darauf ankommt, (ich bin derzeit an gefunden etwas, wo ich habe Mikro-Optimierung alles!).
Um eine komplette Anleitung siehe Gleichheit prüft zur Umsetzung finden Sie unter Was ist "Best Practice" für zwei Instanzen eines Referenztyp Vergleich?
die statische Methode Equals(Object, Object)
ob zwei Objekte anzeigt, und objA
objB
, sind gleich. Es ermöglicht Ihnen auch Objekte, deren Wert zu testen, wird null
auf Gleichheit. Er vergleicht objA
und objB
für die Gleichstellung wie folgt:
- Sie bestimmt, ob die beiden Objekte die gleiche Objektreferenz darstellen. Wenn sie das tun, gibt die Methode
true
. Dieser Test entspricht dasReferenceEquals
Verfahren zu nennen. Darüber hinaus, wenn beideobjA
undobjB
null
sind, gibt die Methodetrue
. - Sie bestimmt, ob entweder
objA
oderobjB
null
ist. Wenn ja, gibt esfalse
. Wenn die beiden Objekte und nicht die gleiche Objektreferenz stellen wedernull
werden, ruft esobjA.Equals(objB)
und gibt das Ergebnis. Dies bedeutet, dass wennobjA
dieObject.Equals(Object)
Methode überschreibt, wird diese Überschreibung genannt.
.
public static bool operator ==(Foo objA, Foo objB) {
return Object.Equals(objA, objB);
}
mehr Antworten auf zwingenden Betreiber, wie zum Vergleich auf null, dass mehrdeutig als Duplikat.
In den Fällen, in denen dies getan wird, um Wertobjekte zu unterstützen, finde ich die neue Schreibweise handlich, und wie es um sicherzustellen, dass nur einen Ort, an dem der Vergleich durchgeführt wird. Auch Object.Equals (A, B) vereinfacht die Null-Kontrollen nutzen.
Dies wird überlasten ==,! =, Equals und GetHashCode
public static bool operator !=(ValueObject self, ValueObject other) => !Equals(self, other);
public static bool operator ==(ValueObject self, ValueObject other) => Equals(self, other);
public override bool Equals(object other) => Equals(other as ValueObject );
public bool Equals(ValueObject other) {
return !(other is null) &&
// Value comparisons
_value == other._value;
}
public override int GetHashCode() => _value.GetHashCode();
Für kompliziertere Objekte hinzufügen, um zusätzliche Vergleiche in Equals und ein reicher GetHashCode.
Es gibt tatsächlich eine einfachere Möglichkeit der Überprüfung gegen null
in diesem Fall:
if (foo is null)
Das ist es!
Dieses Feature wurde in C # eingeführt 7
Ein häufiger Fehler bei Überlastung des Operators == ist
(a == b)
,(a ==null)
oder(b == null)
zu verwenden als Referenz Gleichheit zu überprüfen. diese statt Ergebnisse ein Aufruf der überladenen Operator ==, eineinfinite loop
verursacht. Verwenden SieReferenceEquals
oder werfen den Typ Objekt zu vermeiden, die Schleife.
Sehen Sie sich diese
// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))// using ReferenceEquals
{
return true;
}
// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))// using casting the type to Object
{
return false;
}
Sie können versuchen, eine Objekteigenschaft zu verwenden und die resultierende Nullreferenceexception zu fangen. Wenn die Eigenschaft Sie versuchen, vererbt wird oder von Object außer Kraft gesetzt, dann funktioniert dies für jede Klasse.
public static bool operator ==(Foo foo1, Foo foo2)
{
// check if the left parameter is null
bool LeftNull = false;
try { Type temp = a_left.GetType(); }
catch { LeftNull = true; }
// check if the right parameter is null
bool RightNull = false;
try { Type temp = a_right.GetType(); }
catch { RightNull = true; }
// null checking results
if (LeftNull && RightNull) return true;
else if (LeftNull || RightNull) return false;
else return foo1.field1 == foo2.field2;
}