C# Equality and Comparisons Published

My new Pluralsight course, C# Equality and Comparisons, has been published this week, bringing my total to 3 courses  with the two existing courses. Math for Programmers and C# Collections Fundamentals.

C# Equality and Comparisons was largely spawned out of the earlier C# Collections course:  Back in February this year, I was writing samples for that course to demonstrate making dictionaries case-insensitive. The easiest way to do that is to supply a case-insensitive equality comparer to the dictionary constructor, like this:

var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

And as I was writing this code, it crossed my mind that, behind the StringComparer.OrdinalIgnoreCase property lies a rich architecture of comparers and equality comparers that – as far as I can tell – very few developers know about.  That lead me to thinking about how hard it is to override object.Equals() correctly (If you override it incorrectly – which is very easy to do – bad things tend to happen – like collections stop working properly), and about how many interfaces Microsoft has defined to evaluate equality or less than/greater than comparisons (amazingly, there are no fewer than 9 interfaces for this).

And before I knew it, the idea for a course all about how to do equality and less than/greater than comparisons correctly was born.  I sent a proposal to Mike Woodring at Pluralsight soon after I’d finished C# Collections Fundamentals; he liked the idea, and the result is now sunning itself amongst Pluralsight’s growing list of courses.

In some ways, it seems astonishing that a course on Equality in C# is necessary. After all, saying if (x == y) seems a fairly basic thing to do.  It can’t be that hard to understand equality, surely?

Unfortunately that innocent looking == operator that smiles cutely at you from throughout almost any C# program really isn’t that innocent. Lurking behind it are some very nasty issues.

Take this for a start: What do you think this code will display?

string text = "Equality ain't easy";
object copy = string.Copy(text);
Console.WriteLine(copy == text);

Did you think this would return true? Maybe you’re thinking that both variables contain exactly the string “equality ain’t easy”, so they are self-evidently equal. Maybe the more experienced of you are mentally further justifying that conclusion by reminding yourselves that equality for strings in C# always compares values, which seems to confirm that the two identical strings will evaluate as equal.

Well if you thought that, then you really need to watch my C# Equality and Comparisons course (not that I’m biased, of course).

Because the above code actually displays false.

EqualityPublished-Equal objects

It displays false because the variable copy is of type object, and for things of type object, == does reference equality, not value equality. Yes, I know copy actually refers to a string, but that doesn’t matter because its declared type is still object. You and I can see it’s a string. Any virtual method would see that it’s a string and work appropriately. But the == operator ain’t virtual. It’s static. And that means it works purely based on the type that the variable is declared as – in this case, object.

On the other hand, if I’d typed the copy variable more explicitly, and declared it as being of type string – but without changing anything else – then the code would have displayed true.

EqualityPublished-Equal strings

Just that one change in the type totally changes how equality behaves.

The code looks a bit contrived, but that’s only so I could show that behaviour very quickly.  That’s seriously the kind of thing that can catch you out if you don’t properly understand how equality works in C#.

In fact this is an example of what I think is an unfortunate design choice in C#: In programming there are really two types of equality: Value equality – where you are testing whether two instances have the same value, and reference equality – where you are testing whether two reference types refer to the same memory location. In the following code, the first == evaluates value equality and the second evaluates reference equality.

int x, y; // assume initialized
if (x == y) { /* etc. */ }

Button btn1, btn2; // assume initialized
if (btn1 == btn2) { /* etc. */  }

Notice there’s no difference in the two == operators – nothing about the syntax tells you that one of them behaves completely differently from the other one. You just have to know.  And that’s the unfortunate design choice I mentioned: There’s no syntactical way in C# to distinguish value equality from reference equality.

There are other issues to throw in. It turns out that equality and inheritance aren’t really compatible with each other (seriously – I kid you not – I’ll blog more about that another day). Add to that that sometimes you need to evaluate equality in different ways (for example, does “apple” equal “Apple”? Sometimes you need equality to ignore the case, sometimes you don’t).  Then throw in the difficulty of working out hash codes correctly (Whenever you override object.Equals(), you need to override object.GetHashCode() too – and doing that correctly is a whole topic in its own right). And you can start to see why I ended up writing an entire Pluralsight course just about equality and comparisons.

This may seem a niche, rather specialist, topic.  And I’m sure because of that, I won’t get nearly as much in royalties from it as I will from my C# Collections Fundamentals course. But it does contain a lot of info that is very useful to know if you want to work with equality correctly and follow best practices – and most importantly, avoid creating equality-related bugs in your code. And watching it will mean you understand an important topic in C# and .NET a lot better than most of your co-workers!   So, assuming you have a Pluralsight subscription, get watching! (Not that I’m biased, of course…)

I’ll leave you with a quiz.  I said earlier that there are 9 interfaces that deal with equality and comparisons. Can you work out what all those interfaces are?  Answers in a few days, in my next blog post.


5 thoughts on “C# Equality and Comparisons Published

  1. Hi Simon i am currently studying on your pluralsight course on equality,
    In the section “Implementing Equality in th Derived Type”
    you wrotte :
    public override bool Equals(object obj)
    if (!base.Equals(obj))
    return false;
    CookedFood rhs = (CookedFood)obj;
    return this._cookingMethod == rhs._cookingMethod;
    And i dont understand why you didnt add the type check like this :
    public override bool Equals(object obj)
    if (!base.Equals(obj))
    return false;
    if (this.GetType() != obj.GetType())
    return false;
    CookedFood rhs = (CookedFood)obj;
    return this._cookingMethod == rhs._cookingMethod;

    Thanks a lot your course is hard but interresting!

    1. Hi Jeremy, the reason I didn’t add the type check explicitly is that – if you’ve done everything correctly, there should be a type check in the call to base.Equals(). There’s no harm in adding an explicit type check if you wish, but it shouldn’t normally be necessary and in my view makes the code a bit more complicated than it needs to be. (Unless you have some reason for not trusting the base.Equals() implementation).

      Enjoy the rest of the course, and apologies for not replying sooner.

      1. hi Simon thanks for the answer !
        I understood now, that the type ´s check can be done at the parent class level.
        I have now finished the equality course , it was hard but i did it!
        Now i am studing the ´Maths for developpers’ course , i cant stop learning now.. thanks a lot!

  2. I just watched it and it is really great course. I love when author goes deep under the hood. You nicely clarified so confusing topic .NET. Many thanks and looking forward for more courses from you.

Comment on this article (your first comment on TechieSimon will be moderated)

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 )

Connecting to %s