Story of Equality in .NET – Part 4

0
28

Introduction

I hope that after reading the previous three posts, you have now understood how the .NET framework deals with the Equality using the virtual Object.Equals method and for most of the value types and for few of Reference types using IEquatable. In this post, we will be discussing the C# equality operator provided by Microsoft. We will explore what the C# Equality operator does and how it works. After reading this post, I hope you will have a better understanding of what it means when you check for equality of two variables using == operator.

We will cover the following things:

  • We will be writing some code for comparing the == operator and Object.Equals behavior for the same parameters to see what happens, and we will see that the result is the same, but the mechanism used for both is different.
  • We will see how C# equality operator works for primitive types.

C# provides inequality operator as well, the syntax for which is !=. We will not be discussing this operator in detail because it is the negation of what equality operator does, so they are not that much different. For example, if a==b evaluates to true then a!=b should evaluate to false and vice versa. Apart from this difference, both the operators work exactly the same way. So, keep in mind that everything we will discuss in this post about equality operator also applies to the inequality operator, it will just inverse the return value.

The equality operator is used when we want to evaluate if two of the variables are equal or not. A lot of developers have a misconception that this operator is basically the same as Object.Equals method, and it is just a syntactical convenience provide by the C# language.

This is not actually true. It is being designed in a way that it often gives the same result by calling Object.Equals but that’s not always the case as the underlying mechanism is completely different.

Background

This article is the continuation of the previous three articles regarding how Equality works in .NET, the purpose is to give developers a more clear understanding on how .NET handles equality for types. You may want to read the previous posts as well:

== Operator and Primitive Types

We will see with example code how the equality operator uses different mechanism in reference to Object.Equals method.

class Program
{ static void Main(String[] args) { int num1 = 5; int num2 = 5; Console.WriteLine(num1.Equals(num2)); Console.WriteLine(num1 == num2); Console.ReadKey(); }
}

We are comparing two integers for equality using both ways, the first using Object.Equals overload for integer and the second one using C# equality operator and we will examine the generated IL code which will help us understand how they are different in mechanism.

Of course, when we will run this program, it will evaluate to true for both the statements, and you can test it on your machine as well. Since both the statements are the same, this makes us believe that both are using Object.Equals and checking two integers for equality.

What Happens Behind the Scenes

As we talked earlier, the == operator and Object.Equals work differently and we are going to see how it is which will be a proof to what we talked earlier. We will examine the IL generated for both the statements after compilation.

One thing to note here is that before doing this, you will need to build your project using Release build not debug, as debug code will generate a lot of unnecessary instructions that are helpful when we need to debug and also in debug build, it will use Object.Equals implementation for both, so that will not help you to see what we will discuss next.

For doing that, open the Visual Studio command prompt, for opening it, go to Start Menu >> All Programs >> Microsoft Visual Studio >> Visual Studio Tools>> Developer Command Prompt.

Type ildasm on the command prompt, this will launch the ildasm which is used to look at the IL code contained in an assembly, it is installed automatically when you install Visual Studio, so you don’t need to do anything for installing it.

Browse the folder where your executable is and open it using File Menu. This will bring up the IL code of your executable.

Expand the Program class and double click the Main method. It will open up the intermediate language for Main method:

You don’t need to understand all the code written in it, if you have not seen IL seen before, that may look complex to you, but you don’t need to understand all the instructions.

We will just look at the lines where the comparison is done for both ways to show you the difference, you can see the following line:

pIL_0007: call instance bool [mscorlib]System.Int32::Equals(int32)

Here, it is calling the Object.Equals implementation provided via IEquatable for integer type, in IL we need to specify the method call using Fully Qualified name, so the above statements say to call Equals method which takes as int32 as parameter and method exists in System.Int32 type and this type exists in mscorlib assembly.

Now look at IL generated for second comparison which was done via equality operator, which is:

IL_0013: ceq

You can see that call to Equals method in Int class is not called in this case, instead we have an IL instruction written ceq which says to compare the two values that are being loaded on the stack right now and perform equality comparison using CPU registers. So, C# equality operator uses ceq statement to do equality check for primitive types and it does not call the Object.Equals implementation provided by that primitive type.

Summary

  • We compared the == operator with Object.Equals method in this post.
  • We saw that using == operator gives us the same result as calling Object.Equals but the underlying mechanism of == operator is different in IL as compared to Object.Equals, which is that it does not use the Object.Equals, instead it uses probably CPU registers to do the comparison.

LEAVE A REPLY