Equals beim Überladen des Gleichheitsoperators überschreiben

     TypeName

OverrideEqualsOnOverloadingOperatorEquals

CheckId

CA2224

Kategorie

Microsoft.Usage

Unterbrechende Änderung

NonBreaking

Ursache

Ein öffentlicher Typ implementiert den Gleichheitsoperator, überschreibt jedoch System.Object.Equals nicht.

Regelbeschreibung

Der Gleichheitsoperator soll die Syntax für den Zugriff auf die Funktionalität der Equals-Methode vereinfachen. Wenn Sie den Gleichheitsoperator implementieren, muss seine Logik mit der Logik von Equals übereinstimmen.

Der C#-Compiler gibt eine Warnung aus, wenn der Code gegen diese Regel verstößt.

Behandlung von Verstößen

Um einen Verstoß gegen diese Regel zu beheben, sollten Sie die Implementierung des Gleichheitsoperators entweder entfernen oder Equals überschreiben und von den beiden Methoden die gleichen Werte zurückgeben lassen. Wenn der Gleichheitsoperator kein inkonsistentes Verhalten einleitet, können Sie den Verstoß beheben, indem Sie eine Implementierung von Equals angeben, mit der die Equals-Methode in der Basisklasse aufgerufen wird.

Warnungsausschluss

Eine Warnung dieser Regel kann gefahrlos ausgeschlossen werden, wenn der Gleichheitsoperator den gleichen Wert wie die geerbte Implementierung von Equals zurückgibt. Der Beispielabschnitt enthält einen Typ, der den Ausschluss einer Warnung dieser Regel gefahrlos ermöglicht.

Beispiel

Das folgende Beispiel zeigt einen Typ mit inkonsistenten Definitionen der Gleichheit. BadPoint ändert die Bedeutung der Gleichheit, indem eine benutzerdefinierte Implementierung des Gleichheitsoperators angegeben wird, überschreibt Equals jedoch nicht, sodass es sich identisch verhält.

using System;

namespace UsageLibrary
{   
    public class BadPoint
    {
        private int x,y, id;
        private static int NextId;
        
        static BadPoint()
        {
            NextId = -1;
        }
        public BadPoint(int x, int y)
        {
            this.x = x;
            this.y = y;
            id = ++(BadPoint.NextId); 
        }
        
        public override string ToString()
        {
            return String.Format("([{0}] {1},{2})",id,x,y);
        }
        
        public int X {get {return x;}}
        
        public int Y {get {return x;}}
        public int Id {get {return id;}}
        
        public override int GetHashCode()
        {
            return id;
        }
        // Violates rule: OverrideEqualsOnOverridingOperatorEquals.
        
        // BadPoint redefines the equality operator to ignore the id value.
        // This is different from how the inherited implementation of 
        // System.Object.Equals behaves for value types. 
        // It is not safe to exclude the violation for this type. 
        public static bool operator== (BadPoint p1, BadPoint p2)
        {
            return ((p1.x == p2.x) && (p1.y == p2.y));
        }
        // The C# compiler and rule OperatorsShouldHaveSymmetricalOverloads require this.
        public static bool operator!= (BadPoint p1, BadPoint p2)
        {
            return !(p1 == p2);
        }
    }
}

Im folgenden Code wird das Verhalten von BadPoint getestet.

using System;

namespace UsageLibrary
{   
    public class TestBadPoint
    {
        public static void Main()
        {
            BadPoint a = new BadPoint(1,1);
            BadPoint b = new BadPoint(2,2);
            BadPoint a1 = a;
            BadPoint bcopy = new BadPoint(2,2);
            
            Console.WriteLine("a =  {0} and b = {1} are equal? {2}", a, b, a.Equals(b)? "Yes":"No");
            Console.WriteLine("a == b ? {0}", a == b ? "Yes":"No");
            Console.WriteLine("a1 and a are equal? {0}", a1.Equals(a)? "Yes":"No");
            Console.WriteLine("a1 == a ? {0}", a1 == a ? "Yes":"No");
            
            // This test demonstrates the inconsistent behavior of == and Object.Equals.
            Console.WriteLine("b and bcopy are equal ? {0}", bcopy.Equals(b)? "Yes":"No");
            Console.WriteLine("b == bcopy ? {0}", b == bcopy ? "Yes":"No");
        }
    }
}

Folgende Ergebnisse werden zurückgegeben:

Ausgabe

a =  ([0] 1,1) and b = ([1] 2,2) are equal? No
a == b ? No
a1 and a are equal? Yes
a1 == a ? Yes
b and bcopy are equal ? No
b == bcopy ? Yes

Das folgende Beispiel zeigt einen Typ, der zwar technisch gegen diese Regel verstößt, sich jedoch nicht inkonsistent verhält.

using System;

namespace UsageLibrary
{
    public struct GoodPoint
    {
        private int x,y;
        
        public GoodPoint(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
        
        public override string ToString()
        {
            return String.Format("({0},{1})",x,y);
        }
        
        public int X {get {return x;}}
        
        public int Y {get {return x;}}
        
        // Violates rule: OverrideEqualsOnOverridingOperatorEquals,
        // but does not change the meaning of equality;
        //  the violation can be excluded.
        
        public static bool operator== (GoodPoint px, GoodPoint py)
        {
            return px.Equals(py);
        }
        
        // The C# compiler and rule OperatorsShouldHaveSymmetricalOverloads require this.
        public static bool operator!= (GoodPoint px, GoodPoint py)
        {
            return !(px.Equals(py));
        }
    }
}

Im folgenden Code wird das Verhalten von GoodPoint getestet.

using System;

namespace UsageLibrary
{ 
    public class TestGoodPoint
    {
        public static void Main()
        {
            GoodPoint a = new GoodPoint(1,1);
            GoodPoint b = new GoodPoint(2,2);
            GoodPoint a1 = a;
            GoodPoint bcopy = new GoodPoint(2,2);
            
            Console.WriteLine("a =  {0} and b = {1} are equal? {2}", a, b, a.Equals(b)? "Yes":"No");
            Console.WriteLine("a == b ? {0}", a == b ? "Yes":"No");
            Console.WriteLine("a1 and a are equal? {0}", a1.Equals(a)? "Yes":"No");
            Console.WriteLine("a1 == a ? {0}", a1 == a ? "Yes":"No");
            
            // This test demonstrates the consistent behavior of == and Object.Equals.
            Console.WriteLine("b and bcopy are equal ? {0}", bcopy.Equals(b)? "Yes":"No");
            Console.WriteLine("b == bcopy ? {0}", b == bcopy ? "Yes":"No");
        }
    }
}

Folgende Ergebnisse werden zurückgegeben:

Ausgabe

a =  (1,1) and b = (2,2) are equal? No
a == b ? No
a1 and a are equal? Yes
a1 == a ? Yes
b and bcopy are equal ? Yes
b == bcopy ? Yes

Verwandte Regeln

Gleichheitsoperator bei Verweistypen nicht überladen

Operatorüberladungen haben benannte Alternativen

Operatoren sollten symmetrische Überladungen haben

GetHashCode beim Überschreiben von Equals überschreiben

Equals überladen beim Überschreiben des Gleichheitsoperators durch einen Werttyp