Skip to content

All types are not compared equally

Here is a bit of a quiz: What does this program print?

using System;
using System.Collections.Generic;
class Person { public String Name { get; set; } }
class Example { static void Main() { var people = new List<Person> { new Person { Name = "George Washington" } };
Console.WriteLine( people.Contains( new Person { Name = "George Washington" })); } }

If you said “True” then unfortunately you would be incorrect – this program prints “False”. Before I explain why this program prints “False” I would like to make one slight change to this program to make it print “True”.

using System;
using System.Collections.Generic;
struct Person { public String Name { get; set; } }
class Example { static void Main() { var people = new List<Person> { new Person { Name = "George Washington" } };
Console.WriteLine( people.Contains( new Person { Name = "George Washington" })); } }

Did you spot it?

If you look carefully you will notice that I changed the Person type to be a struct instead of a class. Why would this make a difference? In order to understand let’s take a brief tour of how C# (and the CLR) handle equality.

Whenever you create a type without overriding the Equals method or implementing the IEquatable<T> interface you relinquish control over how two instances of your type will be compared and accept the CLR’s default comparison mechanisms. If your type is a reference type (a class) you will get identity equality and if your type is a value type (a struct) you will get value equality.

Identity equality

Reference types are called reference types because the object itself is stored on the managed heap and you access that object via a reference to that object.

When you compare two instances of a reference type (like the Person type in my first example) the CLR will compare the references to the objects to see if the references point to the same object. Two reference types will only be equal if their reference point to the exact same object on the managed heap. If the references are different the objects are not equal then neither are the objects – even if their fields are identical.

Identity equality asks this question:

Do these two references point to the same object on the managed heap?

Value equality

Value equality is a different process but is actually much simpler to understand. Value equality takes all instance fields of a value type and compares them to the instance fields of a second instance in respective order. I would imagine that value equality works much the way most developers expect all equality checks ought to.

Value equality asks this question:

For each field in these two instances, are all the values equal?

So does this mean that in order to have value equality we must use value types? Of course not! I will soon publish a follow-up article explaining the proper way to implement value equality semantics with reference types.

Edit: Here is the follow-up article: All types are not compared equally (part 2).

2 Comments

  1. Dan Leonard

    Another great article. Can’t wait for the followup!

    Posted on 29-Oct-09 at 8:18 am | Permalink
  2. Ryan

    It might be a good idea to replace the words “references point to…” with “references refer to…”. Using the phrase “point to” sounds like we are dealing with pointers or addresses, whereas how references are implemented is an implementation detail. See http://blogs.msdn.com/ericlippert/archive/2009/02/17/references-are-not-addresses.aspx

    Posted on 28-Apr-10 at 10:54 am | Permalink

Post a Comment

Your email is never published nor shared. Required fields are marked *
*
*