.NET Tips and Tricks

Blog archive

Control Testing for Equality with the IEquatable Interface

When you use the equals sign (=) or the Equals method to compare two objects, you're probably doing a reference comparison: You're asking if the two variables being compared are pointing to the same single object in memory. That may not be what you want.

What you may want is to compare two different instances of the same object to see if the two objects represent the same business entity. As an example, you might compare the variables Customer1 and Customer2, both of which point to Customer objects, to determine if both Customer objects represent the same customer. In that case, you want to do a value comparison: You want to ask if the two objects that the variables point to have identical values in their properties.

You can take control of that comparison in your custom classes by having them implement the IEquatable interface, which contains a single method called Equals. When code compares your object to another object of the same type, the Equals method will be called and be passed the other object. In the Equals method you just need to return False if any two properties on the objects are different. So, for a Customer object, an implementation might look like this:

Class Customer
    Implements IEquatable (Of Customer)

  Public Function Equals1(
        ByVal cust As Customer) _
        As Boolean _
        Implements IEquatable(Of Customer).Equals

   If cust.ID <> this.ID OrElse
      cust.FirstName <> this.FirstName OrElse
      cust.LastName <> this.LastName Then 
            Return False 
    End If 
    Return True 
  End Function 

End Class

However, the IEquatable interface version of the Equals method is used only when the variables are declared with the same data type (i.e., both variables are declared as Customer). If you compare a Customer to a variable of some other type (e.g., compare a variable declared as Customer to a variable declared as Object), then the base Equals method (the one that your class inherits from System.Object) will be used to compare the two objects. At that point, you're probably back to doing a reference comparison.

That behavior may be what you want: Customer to Customer comparisons will be value based and any other comparison will be reference based. But if you think developers using your objects may find this behavior inconsistent, you should also override the default Equals method and call your comparison code from that override also:

Public Function Equals1(
        ByVal cust As Customer) _
        As Boolean _
        Implements IEquatable(Of Customer).Equals
  Return MyValueComparison(CType(obj, Customer));
End Function

Public Overrides Function Equals(obj As Object) As Boolean
  Return MyValueComparison(CType(obj, Customer));
End Function

Public Function MyVallueComparison(cust As Customer) As Boolean
  If cust.ID <> this.ID OrElse
     cust.FirstName <> this.FirstName OrElse
     cust.LastName <> this.LastName Then 
       Return False 
  End If 
  Return True 
End Function

If you override the Equals method, you should override the GetHashCode method so that its results are consistent with the Equals method:

Public Overrides Function GetHashCode() As Integer
  Dim hash As Integer
  '…calculate hashcode and store in hash
  Return hash.GetHashCode()
End Function

You don't need to write a complicated GetHashCode method. The critical issue in overriding the GetHashCode method is to ensure that two objects that are the same (according to the Equals methods) return the same values from GetHashCode. It's not absolutely essential that two different objects return different values from GetHashCode. If your GetHashCode method always returns the same value, you'll have a "good enough" version.

The Dictionary object provides an example of how the value returned from GetHashCode is used. The Dictionary initially uses the hash code to reduce the time to find an object when searching by key. However, if two objects have the same hash code, the Dictionary falls back on the Equals method to find the right object. Using the Equals method will take the Dictionary longer than using the hash code, but you probably won't notice unless you have a lot of objects in the Dictionary.

Posted by Peter Vogel on 07/16/2013


comments powered by Disqus

Featured

Subscribe on YouTube