CA2224 : Remplacez Equals au moment de surcharger l'opérateur égalCA2224: Override equals on overloading operator equals

TypeNameTypeName OverrideEqualsOnOverloadingOperatorEqualsOverrideEqualsOnOverloadingOperatorEquals
CheckIdCheckId CA2224CA2224
CategoryCategory Microsoft.UsageMicrosoft.Usage
Modification avec ruptureBreaking Change Sans ruptureNon Breaking

CauseCause

Un type public implémente l’opérateur d’égalité, mais ne remplace pas System.Object.Equals.A public type implements the equality operator, but does not override System.Object.Equals.

Description de la règleRule Description

L’opérateur d’égalité est destinée à être un moyen pratique de point de vue syntaxique pour accéder aux fonctionnalités de la Equals (méthode).The equality operator is intended to be a syntactically convenient way to access the functionality of the Equals method. Si vous implémentez l’opérateur d’égalité, sa logique doit être identique à celui de Equals.If you implement the equality operator, its logic must be identical to that of Equals.

Le compilateur c# émet un avertissement si votre code ne respecte pas cette règle.The C# compiler issues a warning if your code violates this rule.

Comment corriger les violationsHow to Fix Violations

Pour corriger une violation de cette règle, vous devez supprimer l’implémentation de l’opérateur d’égalité ou substituer Equals et ont les deux méthodes retournent les mêmes valeurs.To fix a violation of this rule, you should either remove the implementation of the equality operator, or override Equals and have the two methods return the same values. Si l’opérateur d’égalité n’introduit aucun comportement incohérent, vous pouvez corriger la violation en fournissant une implémentation de Equals qui appelle le Equals méthode dans la classe de base.If the equality operator does not introduce inconsistent behavior, you can fix the violation by providing an implementation of Equals that calls the Equals method in the base class.

Quand supprimer les avertissementsWhen to Suppress Warnings

Il est possible de supprimer un avertissement de cette règle si l’opérateur d’égalité retourne la même valeur que l’implémentation héritée de Equals.It is safe to suppress a warning from this rule if the equality operator returns the same value as the inherited implementation of Equals. La section exemple inclut un type qui pourrait supprimer sans risque un avertissement de cette règle.The Example section includes a type that could safely suppress a warning from this rule.

Exemples de définitions d’égalité incohérentesExamples of Inconsistent Equality Definitions

DescriptionDescription

L’exemple suivant montre un type avec des définitions d’égalité incohérentes.The following example shows a type with inconsistent definitions of equality. BadPoint Modifie la signification d’égalité en fournissant une implémentation personnalisée de l’opérateur d’égalité, mais ne remplace pas Equals afin qu’il se comporte de façon identique.BadPoint changes the meaning of equality by providing a custom implementation of the equality operator, but does not override Equals so that it behaves identically.

CodeCode

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);
        }
    }
}

ExempleExample

Le code suivant teste le comportement de BadPoint.The following code tests the behavior of BadPoint.

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");
        }
    }
}

Cet exemple produit la sortie suivante.This example produces the following output.

a = ([0] 1,1) et b = ([1] 2,2) sont égaux ? Ne un == b ? Ne a1 et a sont égaux ? Oui a1 == un ? Oui b et b copie sont égaux ? Ne b == bcopy ? Ouia = ([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

ExempleExample

L’exemple suivant montre un type qui viole cette règle techniquement, mais ne se comporte pas de façon incohérente.The following example shows a type that technically violates this rule, but does not behave in an inconsistent manner.

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));
        }
    }
}

ExempleExample

Le code suivant teste le comportement de GoodPoint.The following code tests the behavior of GoodPoint.

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");
        }
    }
}

Cet exemple produit la sortie suivante.This example produces the following output.

a = (1,1) et b = (2,2) sont égaux ? Ne un == b ? Ne a1 et a sont égaux ? Oui a1 == un ? Oui b et b copie sont égaux ? Oui b == bcopy ? Ouia = (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

Exemple de classeClass Example

DescriptionDescription

L’exemple suivant montre une classe (type référence) qui enfreint cette règle.The following example shows a class (reference type) that violates this rule.

CodeCode

using System; 

namespace Samples
{    
    // Violates this rule    
    public class Point    
    {        
        private readonly int _X;        
        private readonly int _Y;         
        
        public Point(int x, int y)        
        {            
            _X = x;            
            _Y = y;        
        }         
        
        public int X        
        {            
            get { return _X; }        
        }         
        
        public int Y        
        {            
            get { return _Y; }        
        }         
        
        public override int GetHashCode()        
        {            
            return _X ^ _Y;        
        }             
        
        public static bool operator ==(Point point1, Point point2)        
        {            
            if (point1 == null || point2 == null)                
                return false;             
                
            if (point1.GetType() != point2.GetType())                
                return false;             
                
            if (point1._X != point2._X)                    
                return false;             
                
            return point1._Y == point2._Y;        
        }         
        
        public static bool operator !=(Point point1, Point point2)        
        {            
            return !(point1 == point2);        
        }    
    }
}

ExempleExample

L’exemple suivant résout la violation en substituant System.Object.Equals.The following example fixes the violation by overriding System.Object.Equals.

using System; 

namespace Samples
{    
    public class Point    
    {        
        private readonly int _X;        
        private readonly int _Y;         
        
        public Point(int x, int y)        
        {            
            _X = x;            
            _Y = y;        
        }         
        
        public int X        
        {            
            get { return _X; }        
        }         
        
        public int Y        
        {            
            get { return _Y; }        
        }         
        
        public override int GetHashCode()        
        {            
            return _X ^ _Y;        
        }         
        
        public override bool Equals(object obj)        
        {            
            if (obj == null)                
                return false;             
                
            if (GetType() != obj.GetType())                
                return false;             
            
            Point point = (Point)obj;             
            
            if (_X != point.X)                
                return false;             
                
            return _Y == point.Y;        
        }         
        
        public static bool operator ==(Point point1, Point point2)        
        {            
            return Object.Equals(point1, point2);        
        }         
        
        public static bool operator !=(Point point1, Point point2)        
        {            
            return !Object.Equals(point1, point2);        
        }    
    }
}

Exemple de structureStructure Example

DescriptionDescription

L’exemple suivant montre une structure (type valeur) qui enfreint cette règle.The following example shows a structure (value type) that violates this rule.

CodeCode

using System; 

namespace Samples
{    
    // Violates this rule    
    public struct Point    
    {        
        private readonly int _X;        
        private readonly int _Y;         
        
        public Point(int x, int y)        
        {            
            _X = x;            
            _Y = y;        
        }         
        
        public int X        
        {            
            get { return _X; }        
        }         
        
        public int Y        
        {            
            get { return _Y; }        
        }         
        
        public override int GetHashCode()        
        {            
            return _X ^ _Y;        
        }         
        
        public static bool operator ==(Point point1, Point point2)        
        {            
            if (point1._X != point2._X)                
                return false;                        
                
            return point1._Y == point2._Y;        
        }         
        
        public static bool operator !=(Point point1, Point point2)        
        {            
            return !(point1 == point2);        
        }    
    }
}

ExempleExample

L’exemple suivant résout la violation en substituant System.ValueType.Equals.The following example fixes the violation by overriding System.ValueType.Equals.

using System; 

namespace Samples
{    
    public struct Point : IEquatable<Point>    
    {        
        private readonly int _X;        
        private readonly int _Y;         
        
        public Point(int x, int y)        
        {            
            _X = x;            
            _Y = y;        
        }         
        
        public int X        
        {            
            get { return _X; }        
        }         
        
        public int Y        
        {            
            get { return _Y; }        
        }         
        
        public override int GetHashCode()        
        {            
            return _X ^ _Y;        
        }         
        
        public override bool Equals(object obj)        
        {            
            if (!(obj is Point))                
                return false;             
                
            return Equals((Point)obj);        
        }         
        
        public bool Equals(Point other)        
        {            
            if (_X != other._X)                
                return false;             
                
            return _Y == other._Y;        
        }         
        
        public static bool operator ==(Point point1, Point point2)        
        {            
            return point1.Equals(point2);        
        }         
        
        public static bool operator !=(Point point1, Point point2)        
        {            
            return !point1.Equals(point2);        
        }    
    }
}

CA1046 : Ne pas surcharger l’opérateur égal sur les types de référenceCA1046: Do not overload operator equals on reference types

CA2225 : Les surcharges d’opérateur ont d’autres méthodes nomméesCA2225: Operator overloads have named alternates

CA2226 : Les opérateurs doivent avoir des surcharges symétriquesCA2226: Operators should have symmetrical overloads

CA2218 : Remplacez GetHashCode lors du remplacement de EqualsCA2218: Override GetHashCode on overriding Equals

CA2231 : Surchargez l’opérateur égal (equals) en remplaçant ValueType.EqualsCA2231: Overload operator equals on overriding ValueType.Equals