Profile picture Schedule a Meeting
c a n d l a n d . n e t

Prefer Equals over operator== because generic types will not behave how you expect

Dusty Candland | |

I stumbled across this unit testing some Immutable model objects. I’m overriding equals on these object and as so thought, how about I create a generic method to test equality? Sounded like a good idea, got rid of some duplicate code, made sure I’m testing all the variations on each object. Then my tests Failed! WTF? It turns out that using == on Generic Type objects is a bad idea, even it you’ve provided you own operator==! Even if you’ve implemented the IEquatable interface!

This is bad:

private static void TestGeneric<T>(T first1, T second1) where T:class 
{
Console.WriteLine("{0} == {1} is {2}", first1, second1, IsTrue(first1 == second1));
}

The compiler will emit IL that does two odd things, IMO. First, box’s the args first1 and first2. That’s a waste as they are constrained to be classes. Second it’s calling the IL method ceq (check equals). Why doesn’t it call Equals()? I’m guessing there are reasons for this, as it’s the same behavior in 3.5. Maybe if you meant to call Equals you should have?

This is good:

private static void TestGeneric<T>(T first1, T second1) where T:class 
{
Console.WriteLine("{0} Equals {1} is {2}", first1, second1, IsTrue(first1.Equals(second1)));
}

The above code won’t box the objects and it will call your overridden Equals method as expected. I know it’s been said before, but alway use the Equals method!

One more interesting thing with the class constraint you can’t use the == syntax. I guess because once the box and class ceq it will break operator== for value types.

Worse is that if your type constraint is a specific class it will allow and call the operator== method but only on that class so any subclass that are passed in will use the base classes operator== for the compare.

Full code to see this in action is attached:

Program1.cs (2.38 KB)

Webmentions

These are webmentions via the IndieWeb and webmention.io. Mention this post from your site: