Implementing your own Linq “equals” join operator

Today I needed to do a Linq join on two sets of class that needed to have a custom join, ie the concept of equality had to be determined by a rule in the class.

The problem is, that .Net doesn’t have an interface that facilitates this, and that you have to have knowledge about the inner workings of the Linq join/equals.

Here is how it works:

1. Linq will call the two compared classes GetHashCode() method to determine if they have the same hash-code.

2. If they don’t they are assumed to be unequal.

3. If the hashcodes are equal, Linq goes on to the class’s Equals(object o) method to determine equality.

This is implemented by reasons of performance. The hash-metod only confirms – as a truly unique hash-code doesn’t exist in reality – that the two classes might be equal, and not until then is the presumably costlier Equals executed to determine acutal equality.

So because of this you need to implement both a GetHashCode() and an Equals() method. By implementing the IEquatable<T>() interface you get the Equals() method, but then you must implement GetHashCode() by overriding it, otherwise your Equals() method may not ever be called as the base GetHashCode() method will be different for all (most) instances, and to Linq all classes will be different!

You can do several things in your GetHashTable() method – the simplest of which is to return a constant, in which case Linq will always quickly move on to the Equals() method. You can also select one or more fields of the class to hash on, I guess it is a design choice based on your knowledge of the actual data that will get the best performance.

Stackoverflow has a good posting here on how to do the hash generation. I personally think this one looked pretty neat:

return new { A = PropA, B = PropB, C = PropC, D = PropD }.GetHashCode(); 

But, as mentioned, it’s all about speed (and memory), and a question whether most elements are actually unequal or equal, so some testing will be in place in each case.


Leave a Reply

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

You are commenting using your 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