Equals Method
.NET Framework Class Library
IEquatable<(Of <(T>)>)..::.Equals Method

Updated: July 2008

Indicates whether the current object is equal to another object of the same type.

Namespace:  System
Assembly:  mscorlib (in mscorlib.dll)
Visual Basic (Declaration)
Function Equals ( _
    other As T _
) As Boolean
Visual Basic (Usage)
Dim instance As IEquatable
Dim other As T
Dim returnValue As Boolean

returnValue = instance.Equals(other)
C#
bool Equals(
    T other
)
Visual C++
bool Equals(
    T other
)
JScript
function Equals(
    other : T
) : boolean

Parameters

other
Type: T
An object to compare with this object.

Return Value

Type: System..::.Boolean
true if the current object is equal to the other parameter; otherwise, false.

The implementation of the Equals method is intended to perform a test for equality with another object of type T, the same type as the current object. The Equals method is called in the following circumstances:

In other words, to handle the possibility that objects of a class will be stored in an array or a generic collection object, it is a good idea to implement IEquatable<(Of <(T>)>) so that the object can be easily identified and manipulated.

When implementing the Equals method, define equality appropriately for the type specified by the generic type argument. For example, if the type argument is Int32, define equality appropriately for the comparison of two 32-bit signed integers.

Notes to Implementers:

If you implement Equals, you should also override the base class implementations of Object..::.Equals(Object) and GetHashCode so that their behavior is consistent with that of the IEquatable<(Of <(T>)>)..::.Equals method. If you do override Object..::.Equals(Object), your overridden implementation is also called in calls to the static Equals(System.Object, System.Object) method on your class. This ensures that all invocations of the Equals method return consistent results, which the example illustrates.

The following example shows the partial implementation of a Person class that implements IEquatable<(Of <(T>)>) and has two properties, LastName and SSN. The Equals method returns True if the SSN property of two Person objects is identical; otherwise, it returns False.

Visual Basic
Imports System.Collections.Generic
Imports System.Text.RegularExpressions

Public Class Person : Implements IEquatable(Of Person)
   Private uniqueSsn As String
   Private lName As String

   Public Sub New(lastName As String, ssn As String)
      Me.SSN = ssn
      Me.LastName = lastName
   End Sub

   Public Property SSN As String
      Set
         If Regex.IsMatch(value, "\d{9}") Then
            uniqueSsn = String.Format("{0}-(1}-{2}", value.Substring(0, 3), _
                                                     value.Substring(3, 2), _
                                                     value.Substring(5, 3))
         ElseIf Regex.IsMatch(value, "\d{3}-\d{2}-\d{3}") Then
            uniqueSsn = value
         Else 
            Throw New FormatException("The social security number has an invalid format.")
         End If
      End Set
      Get
         Return Me.uniqueSsn
      End Get      
   End Property

   Public Property LastName As String
      Get
         Return Me.lName
      End Get
      Set
         If String.IsNullOrEmpty(value) Then
            Throw New NullReferenceException("The last name cannot be null or empty.")
         Else
            lname = value
         End If   
      End Set
   End Property

   Public Overloads Function Equals(other As Person) As Boolean _
                   Implements IEquatable(Of Person).Equals
      If Me.uniqueSsn = other.SSN Then
         Return True
      Else
         Return False
      End If
   End Function

   Public Overrides Function Equals(obj As Object) As Boolean
      If obj Is Nothing Then Return MyBase.Equals(obj)

      If Not TypeOf obj Is Person
         Throw New InvalidCastException("The 'obj' argument is not a Person object.")
      Else
         Return Equals(DirectCast(obj, Person))   
      End If
   End Function   

   Public Overrides Function GetHashCode() As Integer
      Return Me.SSN.GetHashCode()
   End Function

   Public Shared Operator = (person1 As Person, person2 As Person) As Boolean
      Return person1.Equals(person2)
   End Operator

   Public Shared Operator <> (person1 As Person, person2 As Person) As Boolean
      Return Not person1.Equals(person2)
   End Operator
End Class

C#
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

public class Person : IEquatable<Person>
{
   private string uniqueSsn;
   private string lName;

   public Person(string lastName, string ssn)
   {
      this.SSN = ssn;
      this.LastName = lastName;
   }

   public string SSN
   {
      get { return this.uniqueSsn; } 
      set {
         if (Regex.IsMatch(value, @"\d{9}"))
            uniqueSsn = String.Format("{1}-(2}-{3}", value.Substring(0, 3), 
                                                     value.Substring(3, 2), 
                                                     value.Substring(5, 3));
         else if (Regex.IsMatch(value, @"\d{3}-\d{2}-\d{3}"))
            uniqueSsn = value;
         else 
            throw new FormatException("The social security number has an invalid format.");
      }
   }

   public string LastName
   {
      get { return this.lName; }
      set {
         if (String.IsNullOrEmpty(value))
            throw new NullReferenceException("The last name cannot be null or empty.");
         else
            lName = value;
      }
   }

   public bool Equals(Person other) 
   {
      if (this.uniqueSsn == other.SSN)
         return true;
      else
         return false;
   }

   public override bool Equals(Object obj)
   {
      if (obj == null) return base.Equals(obj);

      if (! (obj is Person))
         throw new InvalidCastException("The 'obj' argument is not a Person object.");
      else
         return Equals(obj as Person);   
   }

   public override int GetHashCode()
   {
      return this.SSN.GetHashCode();
   }

   public static bool operator ==(Person person1, Person person2)
   {
      return person1.Equals(person2);
   }

   public static bool operator !=(Person person1, Person person2)
   {
      return (! person1.Equals(person2));
   }
}

Person objects can then be stored in a List<(Of <(T>)>) object and can be identified by the Contains method, as the following example shows.

Visual Basic
Module TestIEquatable
   Public Sub Main()
      ' Create a Person object for each job applicant.
      Dim applicant1 As New Person("Jones", "099-29-4999")
      Dim applicant2 As New Person("Jones", "199-29-3999")
      Dim applicant3 As New Person("Jones", "299-49-6999")

      ' Add applicants to a List object.
      Dim applicants As New List(Of Person)
      applicants.Add(applicant1)
      applicants.Add(applicant2)
      applicants.Add(applicant3)

      ' Create a Person object for the final candidate.
      Dim candidate As New Person("Jones", "199-29-3999")

      If applicants.Contains(candidate) Then
         Console.WriteLine("Found {0} (SSN {1}).", _
                            candidate.LastName, candidate.SSN)
      Else
         Console.WriteLine("Applicant {0} not found.", candidate.SSN)
      End If         

      ' Call the shared inherited Equals(Object, Object) method.
      ' It will in turn call the IEquatable(Of T).Equals implementation.
      Console.WriteLine("{0}({1}) already on file: {2}.", _ 
                        applicant2.LastName, _
                        applicant2.SSN, _
                        Person.Equals(applicant2, candidate)) 
   End Sub
End Module
' The example displays the following output:
'       Found Jones (SSN 199-29-3999).
'       Jones(199-29-3999) already on file: True.

C#
public class TestIEquatable
{
   public static void Main()
   {
      // Create a Person object for each job applicant.
      Person applicant1 = new Person("Jones", "099-29-4999");
      Person applicant2 = new Person("Jones", "199-29-3999");
      Person applicant3 = new Person("Jones", "299-49-6999");

      // Add applicants to a List object.
      List<Person> applicants = new List<Person>();
      applicants.Add(applicant1);
      applicants.Add(applicant2);
      applicants.Add(applicant3);

      // Create a Person object for the final candidate.
      Person candidate = new Person("Jones", "199-29-3999");

      if (applicants.Contains(candidate))
         Console.WriteLine("Found {0} (SSN {1}).", 
                            candidate.LastName, candidate.SSN);
      else
         Console.WriteLine("Applicant {0} not found.", candidate.SSN);

      // Call the shared inherited Equals(Object, Object) method.
      // It will in turn call the IEquatable(Of T).Equals implementation.
      Console.WriteLine("{0}({1}) already on file: {2}.",  
                        applicant2.LastName, 
                        applicant2.SSN, 
                        Person.Equals(applicant2, candidate)); 
   }
}
// The example displays the following output:
//       Found Jones (SSN 199-29-3999).
//       Jones(199-29-3999) already on file: True.

Windows 7, Windows Vista, Windows XP SP2, Windows XP Media Center Edition, Windows XP Professional x64 Edition, Windows XP Starter Edition, Windows Server 2008 R2, Windows Server 2008, Windows Server 2003, Windows Server 2000 SP4, Windows Millennium Edition, Windows 98, Windows CE, Windows Mobile for Smartphone, Windows Mobile for Pocket PC, Xbox 360, Zune

The .NET Framework and .NET Compact Framework do not support all versions of every platform. For a list of the supported versions, see .NET Framework System Requirements.

.NET Framework

Supported in: 3.5, 3.0, 2.0

.NET Compact Framework

Supported in: 3.5, 2.0

XNA Framework

Supported in: 3.0, 2.0, 1.0

Date

History

Reason

July 2008

Added detail on usage and callbacks.

Information enhancement.

July 2008

Added an example.

Information enhancement.

Tags What's this?: Add a tag
Community Content   What is Community Content?
Add new content RSS  Annotations
Issues when using IEquatable in WPF      Steve Solomon   |   Edit   |   Show History

There are some things to be aware of when using this inteface in WPF. When overriding the Equals method from the base Object, the samples show comparing the obj parameter to null, otherwise it attempts to cast to the typed object and call the typed Equals implmentation. eg.

if (obj == null) return base.Equals(obj);
if (!(obj is Currency))
throw new InvalidCastException("The 'obj' argument is not a Currency object.");
return Equals(obj as Currency);

However, if using the object in WPF, especially in a binding scenario, it is possible that obj will be DependencyProperty.UnsetValue. It will therefore fail the null check, but is not of type Currency (the generic type defined), and will therefore raise the InvalidCastException. This can be remedied by altering the code as follows:

if (obj == null || obj == DependencyProperty.UnsetValue) return base.Equals(obj);
if (!(obj is Currency))
throw new InvalidCastException("The 'obj' argument is not a Currency object.");
return Equals(obj as Currency);

On another note. In the expample when overrding the == operator, a simple comparison is done by calling the Equals method on person1. eg.

public static bool operator ==(Person person1, Person person2)
{
return person1.Equals(person2);
}

This is wrong however, as it is perfectly reasonable to expect that either person1 may be null, especially if you are explicitly testing for null, e.g.

string code = _currency == null ? null : _currency.CurrencyCode;

Therefore, you need to test for null, or check for equality using the static base Equals method.

public static bool operator ==(Person person1, Person person2)
{
return Equals(person1, person2);
}
Tags What's this?: Add a tag
Flag as ContentBug
Object.Equals should not throw      danf   |   Edit   |   Show History
In the example above, the implementation of Object.Equals will throw:

if (! (obj is Person))
throw new InvalidCastException("The 'obj' argument is not a Person object.");

This goes against the requirement here (http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx) that states: "Implementations of Equals must not throw exceptions."


Tags What's this?: Add a tag
Flag as ContentBug
It seems okay to throw      PGP   |   Edit   |   Show History
danf,
If you view the "implementation" of equals as the Equals(Person) rather than the Equals(object) and consider that Equals(object) is doing pre-conditions, the exception for invalid cast makes sense. The general guideline suggests not to throw an exception from the actual implementation of Equals. Also consider the base implementation throws a NullReferenceException which when argued this way also looks like it contradicts guidelines.

One suggestion for improvement in this example would be to make the bool Equals(Person) method protected rather than public. Keeping it public will skip all the pre-conditions and base forwards put into Equals(object) which is needed - if called with a type Person.

Tags What's this?: Add a tag
Flag as ContentBug
Operator Overloads      r3volt   |   Edit   |   Show History
Steve Solomon noted earlier that the overloaded operators should throw to the object base class for comparison, the only problem with this is that you cannot therefore use the overriden object.Equals() and local derived class to do this comparison.

Providing this for review:

public static bool operator ==( DerivedClass obj1, DerivedClass obj2 ) { 
    if( (object) obj1 != null && (object) obj2 != null ) { 
        return obj1.Equals( obj2 ); 
    }
    else { 
        return Equals( obj1, obj2 ); 
    }
}

Comments welcome --- it's not pretty and isn't ideal but does allow you to use the base comparisons when there are cases where they cannot be handled by the derived ones.
Tags What's this?: Add a tag
Flag as ContentBug
Processing
Page view tracker