War diese Seite hilfreich?
Ihr Feedback ist uns wichtig. Teilen Sie uns Ihre Meinung mit.
Weiteres Feedback?
1500 verbleibende Zeichen
Richtlinien zum Überladen von Equals() und des ==-Operators

Richtlinien zum Überladen von Equals() und des ==-Operators (C#-Programmierhandbuch)

In C# gibt es zwei verschiedene Arten von Gleichheit: Verweisgleichheit und Wertgleichheit. Wertgleichheit entspricht der üblichen Bedeutung von Gleichheit: Zwei Objekte enthalten die gleichen Werte. Zum Beispiel haben zwei ganze Zahlen mit dem Wert 2 Wertgleichheit. Verweisgleichheit bedeutet, dass keine zwei vergleichbaren Objekte vorhanden sind. Stattdessen gibt es zwei Objektverweise, die beide auf dasselbe Objekt verweisen. Dies kann durch einfache Zuweisung auftreten, wie im folgenden Beispiel gezeigt:

System.Object a = new System.Object();
System.Object b = a;
System.Object.ReferenceEquals(a, b);  //returns true

In diesem Code ist nur ein Objekt vorhanden, aber es gibt mehrere Verweise auf dieses Objekt: a und b. Da beide auf dasselbe Objekt verweisen, weisen sie Verweisgleichheit auf. Wenn zwei Objekte über Verweisgleichheit verfügen, besteht zwischen ihnen auch Wertgleichheit – umgekehrt garantiert Wertgleichheit jedoch keine Verweisgleichheit.

Mit ReferenceEquals können Sie auf Verweisgleichheit prüfen. Um auf Wertgleichheit zu prüfen, verwenden Sie Equals oder Equals.

Equals ist eine virtuelle Methode, mit der jede Klasse ihre Implementierung überschreiben kann. Jede Klasse, die einen Wert (unabhängig vom Werttyp) oder eine Reihe von Werten als Gruppe (z. B. eine komplexe Zahlenklasse) repräsentiert, sollte Equals überschreiben. Wenn der Typ IComparable implementiert, muss Equals überschrieben werden.

Die neue Implementierung von Equals muss alle Garantien von Equals erfüllen:

  • x.Equals(x) gibt true zurück.

  • x.Equals(y) gibt den gleichen Wert wie y.Equals(x) zurück.

  • Wenn (x.Equals(y) && y.Equals(z)) true zurückgibt, dann gibt x.Equals(z) true zurück.

  • Aufeinander folgende Aufrufe von x.Equals(y) geben den gleichen Wert zurück – vorausgesetzt, die Objekte werden nicht verändert, auf die x und y verweisen.

  • x.Equals(NULL) gibt false zurück.

Die neue Implementierung von Equals darf keine Ausnahmen auslösen. Es wird empfohlen, dass jede Klasse, die Equals überschreibt, auch System.Object.GetHashCode überschreiben sollte. Außerdem sollte jede Klasse ergänzend zur Implementierung von Equals(Objekt) auch Equals(Typ) für ihre eigenen Typen zur Verbesserung der Leistung implementieren. Beispiel:

class TwoDPoint : System.Object
{
    public readonly int x, y;

    public TwoDPoint(int x, int y)  //constructor
    {
        this.x = x;
        this.y = y;
    }

    public override bool Equals(System.Object obj)
    {
        // If parameter is null return false.
        if (obj == null)
        {
            return false;
        }

        // If parameter cannot be cast to Point return false.
        TwoDPoint p = obj as TwoDPoint;
        if ((System.Object)p == null)
        {
            return false;
        }

        // Return true if the fields match:
        return (x == p.x) && (y == p.y);
    }

    public bool Equals(TwoDPoint p)
    {
        // If parameter is null return false:
        if ((object)p == null)
        {
            return false;
        }

        // Return true if the fields match:
        return (x == p.x) && (y == p.y);
    }

    public override int GetHashCode()
    {
        return x ^ y;
    }
}

Jede abgeleitete Klasse, die Equals auf der Basisklasse aufrufen kann, sollte dies vor Beenden des Vergleichs tun. Im folgenden Beispiel wird base. Equals von Equals aufgerufen, das auf einen NULL-Parameter prüft und den Parametertyp mit dem Typ der abgeleiteten Klasse vergleicht. Damit fällt der Equals-Implementierung auf der abgeleiteten Klasse die Aufgabe zu, das neue Datenfeld zu prüfen, das auf der abgeleiteten Klasse deklariert ist:

class ThreeDPoint : TwoDPoint
{
    public readonly int z;

    public ThreeDPoint(int x, int y, int z)
        : base(x, y)
    {
        this.z = z;
    }

    public override bool Equals(System.Object obj)
    {
        // If parameter cannot be cast to ThreeDPoint return false:
        ThreeDPoint p = obj as ThreeDPoint;
        if ((object)p == null)
        {
            return false;
        }

        // Return true if the fields match:
        return base.Equals(obj) && z == p.z;
    }

    public bool Equals(ThreeDPoint p)
    {
        // Return true if the fields match:
        return base.Equals((TwoDPoint)p) && z == p.z;
    }

    public override int GetHashCode()
    {
        return base.GetHashCode() ^ z;
    }
}

Der ==-Operator prüft standardmäßig auf Verweisgleichheit, indem er feststellt, ob zwei Verweise auf dasselbe Objekt zeigen. Verweistypen brauchen also den ==-Operator nicht zu implementieren, um diese Funktionalität zu erhalten. Wenn ein Typ unveränderlich ist, d. h., die in der Instanz enthaltenen Daten nicht geändert werden können, kann ein Überladen des ==-Operators zum Prüfen der Wertgleichheit statt der Verweisgleichheit nützlich sein. Der Grund dafür ist, dass bei unveränderlichen Objekten davon ausgegangen werden kann, dass sie identisch sind, wenn sie identische Werte haben. Vom Überschreiben des ==-Operators bei nicht unveränderlichen Typen wird abgeraten.

Implementierungen von überladenen ==-Operatoren dürfen keine Ausnahmen auslösen. Jeder Typ, der den ==-Operator überlädt, muss auch den !=-Operator überladen. Beispiel:

//add this code to class ThreeDPoint as defined previously
//
public static bool operator ==(ThreeDPoint a, ThreeDPoint b)
{
    // If both are null, or both are same instance, return true.
    if (System.Object.ReferenceEquals(a, b))
    {
        return true;
    }

    // If one is null, but not both, return false.
    if (((object)a == null) || ((object)b == null))
    {
        return false;
    }

    // Return true if the fields match:
    return a.x == b.x && a.y == b.y && a.z == b.z;
}

public static bool operator !=(ThreeDPoint a, ThreeDPoint b)
{
    return !(a == b);
}

NoteHinweis

Ein häufiger Fehler bei der Überladung des ==-Operators ist die Verwendung von (a == b), (a == null) oder (b == null), um auf Verweisgleichheit zu überprüfen. Dies führt stattdessen zu einem Aufruf des überladenen ==-Operators und verursacht eine Endlosschleife. Um dies zu vermeiden, verwenden Sie ReferenceEquals, oder wandeln Sie den Typ in Object um.

Anzeigen:
© 2015 Microsoft