Story of Equality in .Net - Part 4
Background:
This article is in the continuation of the previous three articles
regarding how Equality works in .Net, the purpose is to have the developers
more clear understanding on how .Net handles equality for types. You may want
to read the previous post as well:
Introduction
I hope that after reading the previous three posts, you have
now understanding 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<T>. 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 what it means when you check for equality of two variable
using == operator.
We will cover the following things:
- We will be writing some code for comparing the == operator and Object.Equals behavior for same parameters to see what happens, and we will see that the result is same, but the mechanism used for both is different
- We will see how C# equality operator works for primitive types.
C# also 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 that we will discuss in this post about equality operator also
applies to the inequality operator as well, it will just inverse the return
value.
The equality operator is used when we want to evaluate that
if two of the variables are equal or not. A lot of developers have
misconception that this operator is basically the same as Object.Equals method,
and it is just a syntactical convenience provide by C# language.
This is not true actually. It is being designed in a way
that it often gives the same result which by calling Object.Equals will give
but that’s not always the case as the underlying mechanism is completely
different.
== Operator and Primitive Types
We will see with example code that 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 way ,
first using Object.Equals overload for integer and 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. As the result of both the statements is
same this makes us believe that both are using Object.Equals and checking two
integers for equality.
What Happens Behind the Scene
As we talked earlier that the == operator and Object.Equals
work differently and we are going to see that 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:
IL_0007: call instance bool
[mscorlib]System.Int32::Equals(int32)
Here it is calling the Object.Equals implementation provided
via IEquatable<int> 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 that 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 calls 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 underlying mechanism of == operator is different in IL as compare to Object.Equals, which is that it does not uses the Object.Equals instead it uses probably cpu registers to do the comparison.