IEquatable and IComparable – tools in the toolbox

So Jamie and I were pair-programming on the new release of our developer framework. The issue came with caching user details.

We would store the current UserDetail (that was generated when a web user logged on) into a List<UserDetail>. Subsequent calls however, were not finding a match in cache, and therefore when out and generated a new UserDetail AND it would not find a match when we went to update the cache too. This made it so we ended up with a ton of duplicate objects in the cache!! In other words, if we did something like this:

List<UserDetail> userDetails = new List<UserDetail>();

if (!userDetails.Contains(userDetailToCache))
{
   
userDetails.Add(userDetailToCache);
}

even if the userDetailToCache was absolutely identical in every way to an item already in that userDetails collection, it would still come back false. Why, you ask? It’s because the .NET compares the HashCode of each instance, and those won’t be the same. So even if two objects are identical in every way, the .NET framework is looking to see if they ARE the same objects, not if they are equivalent.

In this case, we wanted to override this, and there are two features I read about and have used before, but it’s been a while. This is a classic example of having a tool in your toolbox. You may not need it on a regular basis, but when you do – it’s the perfect tool for the job!

So, in this case, we wanted to use the code above – but change how that “.Contains()” works. Well, .Contains actually just calls the default .Equals() method – which again uses the hash code. The solution then, is to have UserDetail implement IEquitable<UserDetail> – and implement our OWN Equals method (overriding the default), like this:

    public bool Equals(UserDetail other)

    {

        bool isSame = true;

 

        if (!FirstName.Equals(other.FirstName, StringComparison.InvariantCultureIgnoreCase))

            isSame = false;

 

        if (!LastName.Equals(other.LastName, StringComparison.InvariantCultureIgnoreCase))

            isSame = false;

 

        if (!Id.Equals(other.Id))

            isSame = false;

 

        return isSame;

    }

What this does is check to see if all of the properties match (or whatever kind of logic you want) – and return a boolean if YOU think they are the same. Here’s what UserDetail might look like now:

    public class UserDetail : IEquatable<UserDetail>

    {

        public String FirstName { get; set; }

 

        public String LastName { get; set; }

 

        public Guid Id { get; set; }

 

 

        public bool Equals(UserDetail other)

        {

            bool isSame = true;

 

            if (!FirstName.Equals(other.FirstName, StringComparison.InvariantCultureIgnoreCase))

                isSame = false;

 

            if (!LastName.Equals(other.LastName, StringComparison.InvariantCultureIgnoreCase))

                isSame = false;

 

            if (!Id.Equals(other.Id))

                isSame = false;

 

            return isSame;

        }

    }

What’s clever about this – is the same code at the top which does the .Contains(), now works correctly and finds a match because it now uses OUR implementation of .Equals(), simply because we implemented that interface!

A similar thing exists for IComparable<T> and the .CompareTo() method. Again, these aren’t used very often, but when you need them, they can be the perfect tool for the job!

Posted in General, Uncategorized

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Archives
Categories

Enter your email address to follow this blog and receive notifications of new posts by email.

Join 5 other followers

%d bloggers like this: