Skip to content
Theory · Value and reference types · lesson 10 of 11

Equality: == and Equals

Take two photocopies of one report. They are two different sheets, but the text on them is the same. Two links to a cloud document, on the other hand, lead to one and the same document. Whether two things are equal depends on the question: "is this the same thing?" or "do they hold the same thing?".

For strings, == answers the second question: it compares the text. For objects of a class, as you saw in the previous theme, == answers the first one. Every object also has the method Equals. What does it answer, and how do structs behave? Let's look at a class first:

C#
Spot a = new Spot();
a.X = 1;
Spot b = new Spot();
b.X = 1;
Spot c = a;
Console.WriteLine(a == b);      // False
Console.WriteLine(a == c);      // True
Console.WriteLine(a.Equals(b)); // False

class Spot { public int X; }

Let's go through the example line by line:

  1. a and b are two different objects with the same field X = 1.
  2. a == b prints False: for a class, == checks whether it is one object and does not compare the fields.
  3. Spot c = a; copies the reference, so a == c prints True: both references lead to one object.
  4. Equals on a class compares references by default too, so the line prints False.

Two kinds of equality

The question "is this the same thing?" and the question "do they hold the same thing?" are two different kinds of equality:

  • reference equality means two references lead to one object, like two links to one cloud document;
  • value equality means the data match, like the text on two photocopies.

For classes, both == and Equals check reference equality by default. Two objects with the same fields are still two objects.

Here the picture with sheets is inexact. A person looking at two photocopies decides which question to ask. C# picks the question for you, by the kind of type: for a class, "is this one object?"; for Equals on a struct, "do the fields match?".

Equals on structs

A struct has no reference to compare: its value is stored right in the variable. That is why Equals on a struct compares all the fields by default:

C#
Point p = new Point();
p.X = 1;
Point q = new Point();
q.X = 1;
Console.WriteLine(p.Equals(q)); // True
q.X = 2;
Console.WriteLine(p.Equals(q)); // False

struct Point { public int X; }

While the fields of p and q match, Equals prints True. Once q.X changes, the points are different.

Two boxes of one number

Boxing creates an object, so two boxed numbers are two different boxes:

C#
object first = 5;
object second = 5;
Console.WriteLine(first == second);      // False
Console.WriteLine(first.Equals(second)); // True

Let's look at the last two lines:

  1. first == second prints False: for variables of type object, the == operator compares references, and there are two boxes.
  2. first.Equals(second) prints True: Equals on a boxed int compares the numbers themselves.

Strings behave differently. string is a reference type, but both == and Equals compare its text: that is how the authors of the string type defined them. A class can decide for itself what == and Equals mean for it.

== or Equals

Interviewers like to ask: how does == differ from Equals? The answer depends on the kind of type:

  • on a class, both compare references by default;
  • on your own struct, Equals compares the fields, while == does not compile unless the struct declares it (the built-in int, double and bool already have it);
  • on string, both compare the text.

Common mistake

Someone tried to compare two structs with ==:

C#
Point m = new Point();
Point n = new Point();
Console.WriteLine(m == n); // ✗
TEXT
error CS0019: Operator '==' cannot be applied to operands of type 'Point' and 'Point'

The program does not compile. For a struct, C# does not know what == means until the struct declares that operator itself. Compare structs with Equals: m.Equals(n) gives true, because all the fields of both points are zero.

Key points

  • For classes, == and Equals check reference equality by default: whether it is one object.
  • Equals on a struct compares all the fields, while == on a struct does not compile without a declaration of its own.
  • Two boxed numbers are two objects: == gives false, and Equals gives true.
  • string compares the text with both == and Equals.