CA2218: переопределяйте GetHashCode при переопределении Equals

Товар Значение
Идентификатор правила CA2218
Категория Microsoft.Usage
Критическое изменение Не критическое

Причина

Открытый тип переопределяет System.Object.Equals, но не System.Object.GetHashCode.

Описание правила

GetHashCode возвращает значение, основанное на текущем экземпляре, которое подходит для хэширования алгоритмов и структур данных, таких как хэш-таблица. Два объекта, которые относятся к одному типу и равны, должны возвращать один и тот же хэш-код, чтобы убедиться, что экземпляры следующих типов работают правильно:

Устранение нарушений

Чтобы устранить нарушение этого правила, предоставьте реализацию GetHashCode. Для пары объектов одного типа необходимо убедиться, что реализация возвращает то же значение, если реализация Equals возвращается true для пары.

Когда лучше отключить предупреждения

Для этого правила отключать вывод предупреждений не следует.

Пример класса

Description

В следующем примере показан класс (ссылочный тип), нарушающий правило.

Код

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

Комментарии

В следующем примере нарушение устраняется путем переопределения GetHashCode().

Код

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

Пример структуры

Description

В следующем примере показана структура (тип значения), которая нарушает это правило.

Код

using System; 

namespace Samples
{    
    // Violates this rule    
    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 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);        
        }    
    }
}

Комментарии

В следующем примере нарушение устраняется путем переопределения GetHashCode().

Код

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: не перегружайте оператор равенства для ссылочных типов

CA2225: для перезагрузок оператора существуют дополнения с именами

CA2226: перегрузки операторов должны быть симметричны

CA2224: переопределяйте равенство при перегрузке оператора равенства

CA2231: перегружать равенство операторов следует при перегрузке ValueType.Equals

См. также