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