.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

  • Creating Reactive Applications in .NET

    In modern applications, data is being retrieved in asynchronous, real-time streams, as traditional pull requests where the clients asks for data from the server are becoming a thing of the past.

  • AI for GitHub Collaboration? Maybe Not So Much

    No doubt GitHub Copilot has been a boon for developers, but AI might not be the best tool for collaboration, according to developers weighing in on a recent social media post from the GitHub team.

  • Visual Studio 2022 Getting VS Code 'Command Palette' Equivalent

    As any Visual Studio Code user knows, the editor's command palette is a powerful tool for getting things done quickly, without having to navigate through menus and dialogs. Now, we learn how an equivalent is coming for Microsoft's flagship Visual Studio IDE, invoked by the same familiar Ctrl+Shift+P keyboard shortcut.

  • .NET 9 Preview 3: 'I've Been Waiting 9 Years for This API!'

    Microsoft's third preview of .NET 9 sees a lot of minor tweaks and fixes with no earth-shaking new functionality, but little things can be important to individual developers.

  • Data Anomaly Detection Using a Neural Autoencoder with C#

    Dr. James McCaffrey of Microsoft Research tackles the process of examining a set of source data to find data items that are different in some way from the majority of the source items.

Subscribe on YouTube