Wie prüfe ich für NULL-Werte in einer ‚==‘ Operator Überlastung ohne unendliche Rekursion?

StackOverflow https://stackoverflow.com/questions/73713

  •  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?

War es hilfreich?

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 das ReferenceEquals Verfahren zu nennen. Darüber hinaus, wenn beide objA und objB null sind, gibt die Methode true.
  • Sie bestimmt, ob entweder objA oder objB null ist. Wenn ja, gibt es false. Wenn die beiden Objekte und nicht die gleiche Objektreferenz stellen weder null werden, ruft es objA.Equals(objB) und gibt das Ergebnis. Dies bedeutet, dass wenn objA die Object.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 ==, eine infinite loop verursacht. Verwenden Sie ReferenceEquals 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;
}

Richtlinien für die Überlastung Equals () und Operator ==

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;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top