Implementing the Equals MethodÂ
For related information on implementing the equality operator (==), see Guidelines for Implementing Equals and the Equality Operator (==).
Override the GetHashCode method to allow a type to work correctly in a hash table.
Do not throw an exception in the implementation of an Equals method. Instead, return false for a null argument.
Follow the contract defined on the Object.Equals Method as follows:
x.Equals(x)
returns true.x.Equals(y)
returns the same value asy.Equals(x)
.(x.Equals(y) && y.Equals(z))
returns true if and only ifx.Equals(z)
returns true.Successive invocations of
x.Equals(y)
return the same value as long as the objects referenced byx
andy
are not modified.x.Equals(null)
returns false.
For some kinds of objects, it is desirable to have Equals test for value equality instead of referential equality. Such implementations of Equals return true if the two objects have the same value, even if they are not the same instance. The definition of what constitutes an object's value is up to the implementer of the type, but it is typically some or all of the data stored in the instance variables of the object. For example, the value of a string is based on the characters of the string; the Equals method of the String class returns true for any two instances of a string that contain exactly the same characters in the same order.
When the Equals method of a base class provides value equality, an override of Equals in a derived class should call the inherited implementation of Equals.
If you are programming in a language that supports operator overloading, and you choose to overload the equality operator (==) for a specified type, that type should override the Equals method. Such implementations of the Equals method should return the same results as the equality operator. Following this guideline will help ensure that class library code using Equals (such as ArrayList and Hashtable) works in a manner that is consistent with the way the equality operator is used by application code.
If you are implementing a value type, you should consider overriding the Equals method to gain increased performance over the default implementation of the Equals method on ValueType. If you override Equals and the language supports operator overloading, you should overload the equality operator for your value type.
If you are implementing reference types, you should consider overriding the Equals method on a reference type if your type looks like a base type, such as
Point
,String
,BigNumber
, and so on. Most reference types should not overload the equality operator, even if they override Equals. However, if you are implementing a reference type that is intended to have value semantics, such as a complex number type, you should override the equality operator.If you implement the IComparable interface on a given type, you should override Equals on that type.
Examples
The following code examples demonstrate implementing, overriding calling and overloading the Equals method.
Implementing the Equals Method
The following code example contains two calls to the default implementation of the Equals method.
Imports System
Class SampleClass
Public Shared Sub Main()
Dim obj1 As New System.Object()
Dim obj2 As New System.Object()
Console.WriteLine(obj1.Equals(obj2))
obj1 = obj2
Console.WriteLine(obj1.Equals(obj2))
End Sub
End Class
using System;
class SampleClass
{
public static void Main()
{
Object obj1 = new Object();
Object obj2 = new Object();
Console.WriteLine(obj1.Equals(obj2));
obj1 = obj2;
Console.WriteLine(obj1.Equals(obj2));
}
}
The output of the preceding code is as follows:
False
True
Overriding the Equals Method
The following code example shows a Point
class that overrides the Equals method to provide value equality and a class Point3D
, which is derived from Point
. Because the Point
class's override of Equals is the first in the inheritance chain to introduce value equality, the Equals method of the base class (which is inherited from Object and checks for referential equality) is not invoked. However, Point3D.Equals
invokes Point.Equals
because Point
implements Equals in a manner that provides value equality.
Namespace Examples.DesignGuidelines.EqualsImplementation
Public Class Point
Protected x As Integer
Protected y As Integer
Public Sub New (xValue As Integer, yValue As Integer)
Me.x = xValue
Me.y = yValue
End Sub
Public Overrides Overloads Function Equals(obj As Object) As Boolean
If obj Is Nothing OrElse Not Me.GetType() Is obj.GetType() Then
Return False
End If
Dim p As Point = CType(obj, Point)
Return Me.x = p.x And Me.y = p.y
End Function
Public Overrides Function GetHashCode() As Integer
Return x Xor y
End Function
End Class
Public Class Point3D
Inherits Point
Private z As Integer
Public Sub New (xValue As Integer, yValue As Integer, zValue As Integer)
MyBase.New(xValue, yValue)
Me.z = zValue
End Sub
Public Overrides Overloads Function Equals(obj As Object) As Boolean
Return MyBase.Equals(obj) And z = CType(obj, Point3D).z
End Function
Public Overrides Function GetHashCode() As Integer
Return MyBase.GetHashCode() Xor z
End Function
End Class
End Namespace
using System;
namespace Examples.DesignGuidelines.EqualsImplementation
{
class Point: object
{
protected int x, y;
public Point(int xValue, int yValue)
{
x = xValue;
y = yValue;
}
public override bool Equals(Object obj)
{
// Check for null values and compare run-time types.
if (obj == null || GetType() != obj.GetType())
return false;
Point p = (Point)obj;
return (x == p.x) && (y == p.y);
}
public override int GetHashCode()
{
return x ^ y;
}
}
class Point3D: Point
{
int z;
public Point3D(int xValue, int yValue, int zValue) : base(xValue, yValue)
{
z = zValue;
}
public override bool Equals(Object obj)
{
return base.Equals(obj) && z == ((Point3D)obj).z;
}
public override int GetHashCode()
{
return base.GetHashCode() ^ z;
}
}
}
The Point.Equals
method checks that the obj argument is not null and that it references an instance of the same type as this object. If either of the checks fail, the method returns false. The Equals method uses the GetType Method to determine whether the run-time types of the two objects are identical. Note that typeof (TypeOf in Visual Basic) is not used here because it returns the static type. If the method had used a check of the form obj is Point
instead, the check would return true in cases where obj is an instance of a class derived from Point
, even though obj and the current instance are not of the same run-time type. Having verified that both objects are of the same type, the method casts obj to type Point
and returns the result of comparing the instance variables of the two objects.
In Point3D.Equals
, the inherited Equals method is invoked before anything else is done. The inherited Equals method verifies that obj is not null, that obj is an instance of the same class as this object, and that the inherited instance variables match. Only when the inherited Equals returns true does the method compare the instance variables introduced in the derived class. Specifically, the cast to Point3D
is not executed unless obj has been determined to be of type Point3D
or a class derived from Point3D
.
Using the Equals Method to Compare Instance Variables
In the previous example, the equality operator (==) is used to compare the individual instance variables. In some cases, it is appropriate to use the Equals method to compare instance variables in an Equals implementation, as shown in the following code example.
Imports System
Class Rectangle
Private a, b As Point
Public Overrides Overloads Function Equals(obj As [Object]) As Boolean
If obj Is Nothing Or Not Me.GetType() Is obj.GetType() Then
Return False
End If
Dim r As Rectangle = CType(obj, Rectangle)
' Use Equals to compare instance variables.
Return Me.a.Equals(r.a) And Me.b.Equals(r.b)
End Function
Public Overrides Function GetHashCode() As Integer
Return a.GetHashCode() ^ b.GetHashCode()
End Function
End Class
using System;
class Rectangle
{
Point a, b;
public override bool Equals(Object obj)
{
if (obj == null || GetType() != obj.GetType()) return false;
Rectangle r = (Rectangle)obj;
// Use Equals to compare instance variables.
return a.Equals(r.a) && b.Equals(r.b);
}
public override int GetHashCode()
{
return a.GetHashCode() ^ b.GetHashCode();
}
}
Overloading the Equality Operator (==) and the Equals Method
In some programming languages, such as C#, operator overloading is supported. When a type overloads the equality operator (==), it should also override the Equals method to provide the same functionality. This is typically accomplished by writing the Equals method in terms of the overloaded equality operator (==), as in the following code example.
public struct Complex
{
double re, im;
public override bool Equals(Object obj)
{
return obj is Complex && this == (Complex)obj;
}
public override int GetHashCode()
{
return re.GetHashCode() ^ im.GetHashCode();
}
public static bool operator ==(Complex x, Complex y)
{
return x.re == y.re && x.im == y.im;
}
public static bool operator !=(Complex x, Complex y)
{
return !(x == y);
}
}
Because Complex
is a C# struct (a value type), it is known that no classes will be derived from Complex
. Therefore, the Equals method does not need to compare the GetType results for each object. Instead it uses the is operator to check the type of the obj parameter.
Portions Copyright 2005 Microsoft Corporation. All rights reserved.
Portions Copyright Addison-Wesley Corporation. All rights reserved.
For more information on design guidelines, see the "Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries" book by Krzysztof Cwalina and Brad Abrams, published by Addison-Wesley, 2005.