18 Stimmen

C#-Objekt ist nicht null, aber (myObject != null) gibt trotzdem false zurück

Ich muss einen Vergleich zwischen einem Objekt und NULL durchführen. Wenn das Objekt nicht NULL ist, fülle ich es mit einigen Daten.

Hier ist der Code:

 if (region != null)
 {
  ....
 }

Dies funktioniert, aber wenn Schleife und Schleife irgendwann die Region Objekt ist NULL (ich kann Daten innerhalb es im Debug-Modus sehen). Im Schritt-für-Schritt-Debugging geht es nicht innerhalb der IF-Anweisung... Wenn ich einen Quick Watch mit dem folgenden Ausdruck ausführe, sehe ich, dass (region == null) false zurückgibt, UND (region != null) ebenfalls false zurückgibt... warum und wie?

Update

Jemand hat darauf hingewiesen, dass das Objekt == und != überladen wurde:

    public static bool operator ==(Region r1, Region r2)
    {
        if (object.ReferenceEquals(r1, null))
        {
            return false;
        }
        if (object.ReferenceEquals(r2, null))
        {
            return false;
        }

        return (r1.Cmr.CompareTo(r2.Cmr) == 0 && r1.Id == r2.Id);
    }

    public static bool operator !=(Region r1, Region r2)
    {
        if (object.ReferenceEquals(r1, null))
        {
            return false;
        }
        if (object.ReferenceEquals(r2, null))
        {
            return false;
        }
        return (r1.Cmr.CompareTo(r2.Cmr) != 0 || r1.Id != r2.Id);
    }

29voto

Michael Burr Punkte 320591

Ist der Operator == und/oder != für die Klasse des Regionsobjekts überladen?

Jetzt, wo Sie den Code für die Überlastungen gepostet haben:

Die Überladungen sollten wahrscheinlich wie folgt aussehen (der Code stammt aus Beiträgen von Jon Skeet y Philip Rieck ):

public static bool operator ==(Region r1, Region r2)
{
    if (object.ReferenceEquals( r1, r2)) {
        // handles if both are null as well as object identity
        return true;
    }

    if ((object)r1 == null || (object)r2 == null)
    {
       return false;
    }        

    return (r1.Cmr.CompareTo(r2.Cmr) == 0 && r1.Id == r2.Id);
}

public static bool operator !=(Region r1, Region r2)
{
    return !(r1 == r2);
}

16voto

Jon Skeet Punkte 1325502

Diese Operator-Überlastungen sind defekt.

Erstens macht es das Leben sehr viel einfacher, wenn != einfach durch den Aufruf von == und die Umkehrung des Ergebnisses implementiert wird.

Zweitens, vor den Nichtigkeitsprüfungen in == sollte es sein:

if (object.ReferenceEquals(r1, r2))
{
    return true;
}

7voto

Philip Rieck Punkte 31977

Die beiden Überlastungen sind falsch

 public static bool operator ==(Region r1, Region r2)
    {
        if (object.ReferenceEquals(r1, null))
        {
            return false;
        }
        if (object.ReferenceEquals(r2, null))
        {
            return false;
        }

        return (r1.Cmr.CompareTo(r2.Cmr) == 0 && r1.Id == r2.Id);
    }

wenn r1 und r2 Null sind, wird der erste Test ( object.ReferenceEquals(r1, null) ) gibt false zurück, auch wenn r2 ebenfalls null ist.

Versuchen Sie

//ifs expanded a bit for readability
 public static bool operator ==(Region r1, Region r2)
    {
        if( (object)r1 == null && (object)r2 == null)
        {
           return true;
        }
        if( (object)r1 == null || (object)r2 == null)
        {
           return false;
        }        
        //btw - a quick shortcut here is also object.ReferenceEquals(r1, r2)

        return (r1.Cmr.CompareTo(r2.Cmr) == 0 && r1.Id == r2.Id);
    }

3voto

skb Punkte 29254

Dies kann vorkommen, wenn mehrere Threads mit denselben Daten arbeiten. Wenn dies der Fall ist, können Sie eine Sperre verwenden, um zu verhindern, dass sie sich gegenseitig stören.

2voto

Triynko Punkte 18016

Für den Gleichheitsvergleich eines Typs "T", überladen Sie diese Methoden:

int GetHashCode() //Overrides Object.GetHashCode
bool Equals(object other) //Overrides Object.Equals; would correspond to IEquatable, if such an interface existed
bool Equals(T other) //Implements IEquatable<T>; do this for each T you want to compare to
static bool operator ==(T x, T y)
static bool operator !=(T x, T y)

Ihr typspezifischer Vergleichscode sollte an einer Stelle erfolgen : die typsichere IEquatable<T> Interface-Methode Equals(T other) . Wenn Sie mit einem anderen Typ (T2) vergleichen, implementieren Sie IEquatable<T2> und setzen Sie den Feldvergleichscode für diesen Typ in Equals(T2 other).

Alle überladenen Methoden und Operatoren sollten die Aufgabe des Gleichheitsvergleichs an die typsichere Hauptinstanzmethode Equals(T other) weiterleiten, so dass eine saubere Abhängigkeitshierarchie beibehalten wird und auf jeder Ebene strengere Garantien eingeführt werden, um Redundanz und unnötige Komplexität zu vermeiden.

bool Equals(object other)
{
    if (other is T) //replicate this for each IEquatable<T2>, IEquatable<T3>, etc. you may implement
        return Equals( (T)other) ); //forward to IEquatable<T> implementation
    return false; //other is null or cannot be compared to this instance; therefore it is not equal
}

bool Equals(T other)
{
    if ((object)other == null) //cast to object for reference equality comparison, or use object.ReferenceEquals
        return false;
    //if ((object)other == this) //possible performance boost, ONLY if object instance is frequently compared to itself! otherwise it's just an extra useless check
        //return true;
    return field1.Equals( other.field1 ) &&
           field2.Equals( other.field2 ); //compare type fields to determine equality
}

public static bool operator ==( T x, T y )
{
    if ((object)x != null) //cast to object for reference equality comparison, or use object.ReferenceEquals
        return x.Equals( y ); //forward to type-safe Equals on non-null instance x
    if ((object)y != null)
        return false; //x was null, y is not null
    return true; //both null
}

public static bool operator !=( T x, T y )
{
    if ((object)x != null)
        return !x.Equals( y ); //forward to type-safe Equals on non-null instance x
    if ((object)y != null)
        return true; //x was null, y is not null
    return false; //both null
}

Diskussion:

Die vorangehende Implementierung zentralisiert den typspezifischen (d.h. feldgleichen) Vergleich an das Ende der IEquatable<T> Implementierung für den Typ. Die == y != Operatoren haben eine parallele, aber entgegengesetzte Implementierung. Ich bevorzuge dies gegenüber einem Verweis auf den anderen, so dass es einen zusätzlichen Methodenaufruf für den abhängigen Operator gibt. Wenn die != Operator wird einfach die == Operator zu verwenden, anstatt einen gleichwertigen Operator anzubieten, dann können Sie auch einfach !(obj1 == obj2) und vermeiden Sie den zusätzlichen Methodenaufruf. Der Vergleich mit sich selbst wird vom Gleichheitsoperator weggelassen und die IEquatable<T> Implementierungen, da es 1. in einigen Fällen zu unnötigem Overhead und/oder 2. zu inkonsistenter Leistung führen kann, je nachdem, wie oft eine Instanz mit sich selbst und anderen Instanzen verglichen wird.

Eine Alternative, die ich nicht mag, aber erwähnen sollte, ist die Umkehrung dieses Aufbaus, die Zentralisierung des typspezifischen Gleichheitscodes im Gleichheitsoperator und die Abhängigkeit der Gleichheitsmethoden von diesem. Man könnte dann die Abkürzung von ReferenceEquals(obj1,obj2) um gleichzeitig auf Referenzgleichheit und Nullgleichheit zu prüfen, wie Philip in einem früheren Beitrag erwähnte, aber diese Idee ist irreführend. Es scheint, als würden Sie zwei Fliegen mit einer Klappe schlagen, aber Sie verursachen tatsächlich mehr Arbeit - nachdem Sie festgestellt haben, dass die Objekte weder beide null noch dieselbe Instanz sind, müssen Sie dann zusätzlich noch prüfen, ob jede Instanz null ist. In meiner Implementierung prüfen Sie genau einmal, ob eine einzelne Instanz null ist. Wenn die Instanzmethode Equals aufgerufen wird, ist bereits ausgeschlossen, dass das erste zu vergleichende Objekt null ist, so dass nur noch geprüft werden muss, ob das andere null ist. Nach höchstens zwei Vergleichen springen wir also direkt in die Feldprüfung, egal welche Methode wir verwenden ( Equals(object),Equals(T),==,!= ). Wie ich bereits erwähnt habe, könnten Sie, wenn Sie wirklich die meiste Zeit ein Objekt mit sich selbst vergleichen, diese Prüfung in der Equals-Methode hinzufügen, bevor Sie in die Feldvergleiche eintauchen. Der Grund für das Hinzufügen als Letztes ist, dass Sie die Fluss-/Abhängigkeitshierarchie beibehalten können, ohne auf jeder Ebene eine redundante/unnötige Prüfung einzuführen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X