CA2218: Override GetHashCode on overriding Equals
The new home for Visual Studio documentation is Visual Studio 2017 Documentation on docs.microsoft.com.
The latest version of this topic can be found at CA2218: Override GetHashCode on overriding Equals.
TypeName|OverrideGetHashCodeOnOverridingEquals|
|CheckId|CA2218|
|Category|Microsoft.Usage|
|Breaking Change|Non Breaking|
A public type overrides Object.Equals but does not override Object.GetHashCode.
GetHashCode returns a value, based on the current instance, that is suited for hashing algorithms and data structures such as a hash table. Two objects that are the same type and are equal must return the same hash code to ensure that instances of the following types work correctly:
T:System.Collections.Generic.Dictionary
T:System.Collections.Generic.SortDictionary
T:System.Collections.Generic.SortList
T:System.Collections.Specialized.HybredDictionary
Types that implement T:System.Collections.Generic.IEqualityComparer
To fix a violation of this rule, provide an implementation of GetHashCode. For a pair of objects of the same type, you must ensure that the implementation returns the same value if your implementation of Equals returns true for the pair.
Do not suppress a warning from this rule.
Description
The following example shows a class (reference type) that violates this rule.
Code
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; } } }
Comments
The following example fixes the violation by overriding T:System.Object.GetHashCode.
Code
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
The following example shows a structure (value type) that violates this rule.
Code
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); } } }
Comments
The following example fixes the violation by overriding T:System.Object.GetHashCode.
Code
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: Do not overload operator equals on reference types
CA2225: Operator overloads have named alternates
CA2226: Operators should have symmetrical overloads
CA2224: Override equals on overloading operator equals
CA2231: Overload operator equals on overriding ValueType.Equals
Object.Equals
Object.GetHashCode
T:System.Collections.HashTable
Equality Operators