CA2224: Reemplazar Equals al sobrecargar operadores de igualdadCA2224: Override equals on overloading operator equals

TypeNameTypeName OverrideEqualsOnOverloadingOperatorEqualsOverrideEqualsOnOverloadingOperatorEquals
Identificador de comprobaciónCheckId CA2224CA2224
CategoríaCategory Microsoft.UsageMicrosoft.Usage
Cambio problemáticoBreaking Change No trascendentalNon Breaking

MotivoCause

Un tipo público implementa el operador de igualdad, pero no reemplaza System.Object.Equals.A public type implements the equality operator, but does not override System.Object.Equals.

Descripción de la reglaRule Description

El operador de igualdad está pensado para ser sintácticamente cómodamente para tener acceso a la funcionalidad de la Equals método.The equality operator is intended to be a syntactically convenient way to access the functionality of the Equals method. Si implementa el operador de igualdad, su lógica debe ser idéntica de Equals.If you implement the equality operator, its logic must be identical to that of Equals.

El compilador de C# emite una advertencia si el código infringe esta regla.The C# compiler issues a warning if your code violates this rule.

Cómo corregir infraccionesHow to Fix Violations

Para corregir una infracción de esta regla, debe quitar la implementación del operador de igualdad o invalidar Equals y dispone de los dos métodos devuelvan los mismos valores.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 el operador de igualdad no presenta un comportamiento incoherente, puede corregir la infracción proporcionando una implementación de Equals que llama el Equals método en la clase 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.

Cuándo suprimir advertenciasWhen to Suppress Warnings

Es seguro suprimir una advertencia de esta regla si el operador de igualdad devuelve el mismo valor que la implementación heredada 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 sección ejemplo incluye un tipo que puede suprimir una advertencia de esta regla de forma segura.The Example section includes a type that could safely suppress a warning from this rule.

Ejemplos de definiciones de igualdad incoherentesExamples of Inconsistent Equality Definitions

DescripciónDescription

En el ejemplo siguiente se muestra un tipo con definiciones incoherentes de igualdad.The following example shows a type with inconsistent definitions of equality. BadPointcambia el significado de igualdad proporcionando una implementación personalizada del operador de igualdad, pero no reemplaza Equals para que se comporta de forma idéntica.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.

CódigoCode

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

EjemploExample

El código siguiente comprueba el comportamiento 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");
        }
    }
}

Este ejemplo produce el siguiente resultado:This example produces the following output.

¿a = (1,1 [0]) y b = (2,2 [1]) son iguales? Noa = ([0] 1,1) and b = ([1] 2,2) are equal? No
¿un == b? Noa == b ? No
¿a1 y a son igual? Sía1 and a are equal? Yes
¿a1 == un? Sía1 == a ? Yes
¿b y bcopy son iguales? Nob and bcopy are equal ? No
¿b == bcopy? Síb == bcopy ? Yes

EjemploExample

En el ejemplo siguiente se muestra un tipo que técnicamente infringe esta regla, pero no se comporta de forma incoherente.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));
        }
    }
}

EjemploExample

El código siguiente comprueba el comportamiento 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");
        }
    }
}

Este ejemplo produce el siguiente resultado:This example produces the following output.

¿a = (1,1) y b = (2,2) son iguales? Noa = (1,1) and b = (2,2) are equal? No
¿un == b? Noa == b ? No
¿a1 y a son igual? Sía1 and a are equal? Yes
¿a1 == un? Sía1 == a ? Yes
¿b y bcopy son iguales? Síb and bcopy are equal ? Yes
¿b == bcopy? Síb == bcopy ? Yes

Ejemplo de la claseClass Example

DescripciónDescription

En el ejemplo siguiente se muestra una clase (tipo de referencia) que infringe esta regla.The following example shows a class (reference type) that violates this rule.

CódigoCode

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

EjemploExample

En el ejemplo siguiente se corrige la infracción invalidando 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);        
        }    
    }
}

Ejemplo de estructuraStructure Example

DescripciónDescription

En el ejemplo siguiente se muestra una estructura (tipo de valor) que infringe esta regla.The following example shows a structure (value type) that violates this rule.

CódigoCode

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

EjemploExample

En el ejemplo siguiente se corrige la infracción invalidando 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: No sobrecargar el operador de igualdad en los tipos de referenciaCA1046: Do not overload operator equals on reference types

CA2225: Las sobrecargas del operador tienen alternativas con nombreCA2225: Operator overloads have named alternates

CA2226: Los operadores deben tener sobrecargar simétricasCA2226: Operators should have symmetrical overloads

CA2218: Invalidar el método GetHashCode al invalidar el método EqualsCA2218: Override GetHashCode on overriding Equals

CA2231: Sobrecargar el operador equals al invalidar ValueType.EqualsCA2231: Overload operator equals on overriding ValueType.Equals